import { getSessionOptions } from "@/lib/cookies";
import { createCoreAPIClient } from "@/lib/features/coreClient";
import type { CoreAPIPagination, CoreResponse } from "@/lib/features/types";
import type { AdminUser } from "@/lib/features/users/types";
import type { ExportMode, ExportSectionKey, UserAccessList } from "./types";

// Re-exported so existing importers of these names keep working.
export type { ExportMode, ExportSectionKey } from "./types";

const coreClient = createCoreAPIClient();

export type KnownPromoCode = { id: string; name: string; isLive: boolean };

// Lists users for the Access List picker via a promocode-access-list:read
// gated endpoint — NOT getAdminUsers()/the settings/users query, which
// requires the much broader user-management permission a user might not have.
export async function getUsersForAccessList(
  page = 1,
  pageSize = 15,
  search?: string,
  request?: Request,
) {
  try {
    const params = new URLSearchParams();
    params.set("page", page.toString());
    params.set("pageSize", pageSize.toString());
    if (search) {
      params.set("searchTerm", search);
    }
    const options = getSessionOptions(request);
    const response = await coreClient<{
      users: AdminUser[];
      pagination: CoreAPIPagination;
    }>(`/v2/admin/console-user-access-list?${params.toString()}`, {
      headers: { ...options },
    });
    return response;
  } catch (error) {
    return {
      message: (error as Error).message ?? "Failed fetching users",
      data: null,
    };
  }
}

// Candidates for the "Add User" picker — active users not already on the
// Access List (and not yourself/a super admin). Separate endpoint from
// getUsersForAccessList(), which now only returns already-added members.
export async function getAccessListCandidates(
  page = 1,
  pageSize = 15,
  search?: string,
  request?: Request,
) {
  try {
    const params = new URLSearchParams();
    params.set("page", page.toString());
    params.set("pageSize", pageSize.toString());
    if (search) {
      params.set("searchTerm", search);
    }
    const options = getSessionOptions(request);
    const response = await coreClient<{
      users: AdminUser[];
      pagination: CoreAPIPagination;
    }>(`/v2/admin/console-user-access-list/candidates?${params.toString()}`, {
      headers: { ...options },
    });
    return response;
  } catch (error) {
    return {
      message: (error as Error).message ?? "Failed fetching candidates",
      data: null,
    };
  }
}

// Union of live Updot promo codes and every code ever attached to a campaign
// locally, even ones since deleted upstream — the Access List picker's data
// source, so historical codes stay assignable.
export async function getAllKnownPromoCodes(
  headers?: HeadersInit,
): Promise<CoreResponse<KnownPromoCode[]>> {
  return await coreClient<KnownPromoCode[]>(
    "/v1/admin-console/promo-code-campaigns/all-known-promo-codes",
    { method: "GET", headers },
  );
}

export type AccessListCampaign = {
  id: string;
  name: string;
  promo_code_count: number;
};

// Unfiltered campaign list for the Access List picker — NOT listCampaigns(),
// which scopes results to the *viewer's* own campaign access and requires
// promo-code-campaigns:read (a permission an access-list-only manager may
// not have).
export async function getAllCampaignsForAccessList(
  headers?: HeadersInit,
): Promise<CoreResponse<AccessListCampaign[]>> {
  return await coreClient<AccessListCampaign[]>(
    "/v1/admin-console/promo-code-campaigns/all-campaigns",
    { method: "GET", headers },
  );
}

export type CampaignPromoCodeMapRow = {
  campaign_id: string;
  campaign_name: string;
  promo_code_id: string;
  promo_code_name: string;
};

// Full, unfiltered campaign→promo-code mapping — lets the Access List detail.
export async function getCampaignPromoCodeMap(
  headers?: HeadersInit,
): Promise<CoreResponse<CampaignPromoCodeMapRow[]>> {
  return await coreClient<CampaignPromoCodeMapRow[]>(
    "/v1/admin-console/promo-code-campaigns/campaign-promo-code-map",
    { method: "GET", headers },
  );
}

export type ExportPermissions = {
  isMember: boolean;
  canExportCampaigns: boolean;
  canExportPromoCodes: boolean;
  canExportMemberReferrals: boolean;
  canExportReports: boolean;
  /**
   * Per-section mode. Supersedes the booleans above, which are kept so older
   * callers keep working; absent for a response from a core that predates it.
   */
  exportModes?: Partial<Record<ExportSectionKey, ExportMode>>;
};

// The current user's own export permissions — non-members (or nobody logged
// in) always get all-true, so this only ever *removes* export ability from
// someone already on the Access List. Not gated by promocode-access-list
// itself, since every user needs to check their own flags.
export async function getMyExportPermissions(
  headers?: HeadersInit,
): Promise<CoreResponse<ExportPermissions>> {
  return await coreClient<ExportPermissions>(
    "/v2/admin/console-user-access-list/me",
    { headers },
  );
}

export async function getUserAccessList(id: string, request: Request) {
  try {
    const options = getSessionOptions(request);
    const response = await coreClient<UserAccessList>(
      `/v2/admin/console-user-access-list/${id}`,
      {
        headers: { ...options },
      },
    );
    return response;
  } catch (error) {
    return {
      message: (error as Error).message ?? "Failed fetching user access list",
      data: null,
    };
  }
}
