import { apiClient } from '@/lib/api';
import { UsersApi } from '@/app/(main)/workspace/users/api';
import type { User } from '@/app/(main)/workspace/users/types';
import type { ShareAdapter, SharedMember, ShareSubmission, ShareUser } from '@/app/components/share/types';
import { useUserStore } from '@/lib/store/user-store';
import { AgentsApi } from '@/app/(main)/agents/api';
import type { SharedWithEntry } from './types';

export interface CreateChatShareAdapterOptions {
  /** When set, uses GET/POST agent conversation share routes instead of global chat. */
  agentId?: string;
}

/**
 * Creates a ShareAdapter for a Chat Conversation.
 * Simple share/unshare — no roles and no team-sharing UI.
 */
export function createChatShareAdapter(
  conversationId: string,
  options?: CreateChatShareAdapterOptions
): ShareAdapter {
  const agentId = options?.agentId;

  const conversationBasePath = agentId
    ? `/api/v1/agents/${agentId}/conversations/${conversationId}`
    : `/api/v1/conversations/${conversationId}`;

  return {
    entityType: 'conversation',
    entityId: conversationId,
    sidebarTitle: 'Share Chat',
    supportsRoles: false,
    supportsTeams: false,

    async getSharedMembers(): Promise<SharedMember[]> {
      // Read lazily from UserStore — populated by UserProfileInitializer on every
      // page load. useAuthStore.user is only set during the login flow itself and
      // is null after a refresh, so it is not a reliable source here.
      const currentUserId = useUserStore.getState().profile?.userId;

      let conversation: {
        sharedWith?: SharedWithEntry[];
        initiator?: string;
        userId?: string;
        ownerId?: string;
      };
      if (agentId) {
        conversation = (await AgentsApi.fetchAgentConversation(agentId, conversationId)).conversation;
      } else {
        const { data } = await apiClient.get(`/api/v1/conversations/${conversationId}/`);
        conversation = data.conversation ?? data;
      }
      const sharedWithEntries: SharedWithEntry[] = conversation.sharedWith ?? [];
      const sharedWithMongoIds = sharedWithEntries.map((entry: SharedWithEntry) => entry.userId);
      const ownerId: string = conversation.initiator ?? conversation.userId ?? conversation.ownerId ?? '';

      if (sharedWithMongoIds.length === 0 && !ownerId) return [];

      // Enrich with user details via batch-by-ids lookup (keyed by MongoDB userId).
      // This avoids the page-1-only cap from fetchMergedUsers when the conversation
      // is shared with users who don't appear in the first page of the org.
      const idsToLookup = Array.from(
        new Set([...sharedWithMongoIds, ...(ownerId ? [ownerId] : [])])
      );
      let users: User[] = [];
      try {
        users = await UsersApi.getUsersByIds(idsToLookup);
      } catch {
        // Fallback: show IDs only
      }
      const userMap = new Map<string, User>(users.map((u) => [u.userId, u]));

      // Build accessLevel lookup from sharedWith entries
      const accessMap = new Map(sharedWithEntries.map((entry: SharedWithEntry) => [entry.userId, entry.accessLevel]));
      const members: SharedMember[] = [];

      // Add owner
      if (ownerId) {
        const ownerData = userMap.get(ownerId.toString());
        members.push({
          id: ownerId.toString(),
          type: 'user',
          name: ownerData?.name ?? ownerData?.email ?? 'Owner',
          email: ownerData?.email,
          avatarUrl: undefined,
          role: 'OWNER',
          isOwner: true,
          isCurrentUser: ownerId === currentUserId,
        });
      }

      // Add shared users
      for (const mongoId of sharedWithMongoIds) {
        if (mongoId === ownerId) continue;
        const userData = userMap.get(mongoId);
        const accessLevel = accessMap.get(mongoId) ?? 'read';
        members.push({
          id: mongoId,
          type: 'user',
          name: userData?.name ?? userData?.email ?? mongoId,
          email: userData?.email,
          avatarUrl: undefined,
          role: accessLevel === 'write' ? 'WRITER' : 'READER',
          isOwner: false,
          isCurrentUser: mongoId === currentUserId,
        });
      }

      return members;
    },

    async share(submission: ShareSubmission): Promise<void> {
      // Chat share currently supports direct-user IDs only.
      const userIdsSet = new Set(submission.userIds);

      // The chat /share endpoint accepts an optional accessLevel ('read' | 'write').
      // The sidebar forces submission.role to 'READER' when supportsRoles is false
      // (our case), but map it explicitly so the backend contract is respected if
      // the adapter is ever flipped to support roles.
      const accessLevel: 'read' | 'write' =
        submission.role === 'WRITER' ? 'write' : 'read';

      await apiClient.post(`${conversationBasePath}/share`, {
        userIds: Array.from(userIdsSet),
        accessLevel,
      });
    },

    async removeMember(memberId: string): Promise<void> {
      await apiClient.post(`${conversationBasePath}/unshare`, {
        userIds: [memberId],
      });
    },

    /**
     * Returns paginated users with MongoDB ObjectIDs as id — required by the chat
     * /share endpoint. Enables infinite scroll in the share sidebar.
     *
     * Uses listGraphUsers (GET /api/v1/users/graph/list), which returns both the
     * graph UUID (u.id) and the MongoDB ObjectId (u.userId). We expose MongoDB
     * as `id` for /share, and the graph UUID as `uuid` for team creation. The
     * plain /api/v1/users endpoint can't be used here: it sets both id and userId
     * to the MongoDB _id, leaving team creation with no valid UUID to submit.
     */
    async getSharingUsersPaginated(params: {
      page: number;
      limit: number;
      search?: string;
    }): Promise<{ users: ShareUser[]; totalCount: number }> {
      const result = await UsersApi.listGraphUsers({
        page: params.page,
        limit: params.limit,
        search: params.search,
      });
      return {
        users: result.users.map((u) => ({
          id: u.userId,   // MongoDB ObjectID — what /share expects
          uuid: u.id,     // Graph UUID — required by team creation
          name: u.name ?? u.email ?? '',
          email: u.email,
          avatarUrl: undefined,
          isInOrg: true,
        })),
        totalCount: result.totalCount,
      };
    },

    // No updateRole — supportsRoles is false
  };
}
