import type { Gender } from "@/lib/api-types";

export type KycAssistMode = "self_serve" | "agent_assisted";

export type OneIdSessionStatus = "pending" | "verified" | "failed";

export interface OneIdOfficialIdentity {
  pinfl: string;
  fullNameOfficial: string;
  dateOfBirthOfficial: string;
  genderOfficial: Gender;
}

export interface OneIdSession {
  sessionId: string;
  pinfl: string;
  status: OneIdSessionStatus;
  kycAssistMode: KycAssistMode;
  official?: OneIdOfficialIdentity;
  createdAt: string;
  verifiedAt?: string;
}

export interface StartOneIdSessionInput {
  pinfl: string;
  redirectUri: string;
  kycAssistMode?: KycAssistMode;
}

export interface StartOneIdSessionResult {
  sessionId: string;
  authorizationUrl: string;
}

export interface HandleOneIdCallbackInput {
  code: string;
  state: string;
}

export interface HandleOneIdCallbackResult {
  session: OneIdSession;
  official: OneIdOfficialIdentity;
}

const ONEID_BASE_URL = process.env.ONEID_BASE_URL ?? "https://sso.oneid.uz";
const ONEID_CLIENT_ID = process.env.ONEID_CLIENT_ID ?? "";

export function isOneIdEnabled(): boolean {
  return process.env.ONEID_ENABLED === "true";
}

export function isPilotKycBypassAllowed(): boolean {
  if (process.env.CORE_API_USE_MOCK === "true" || process.env.PLAYWRIGHT === "1") {
    return true;
  }
  // Local dev without OneID — unblock onboarding with mock verification.
  return process.env.NODE_ENV === "development" && !isOneIdEnabled();
}

const PINFL_PATTERN = /^[0-9]{14}$/;

export function isValidPinfl(pinfl: string): boolean {
  return PINFL_PATTERN.test(pinfl);
}

export async function startSession(
  input: StartOneIdSessionInput,
): Promise<StartOneIdSessionResult> {
  if (!isOneIdEnabled()) {
    throw new Error("OneID is not enabled");
  }
  if (!ONEID_CLIENT_ID) {
    throw new Error("ONEID_CLIENT_ID is not configured");
  }
  if (!isValidPinfl(input.pinfl)) {
    throw new Error("PINFL must be 14 digits");
  }

  const sessionId = crypto.randomUUID();
  const state = Buffer.from(
    JSON.stringify({
      sessionId,
      pinfl: input.pinfl,
      kycAssistMode: input.kycAssistMode ?? "self_serve",
    }),
  ).toString("base64url");

  const params = new URLSearchParams({
    client_id: ONEID_CLIENT_ID,
    response_type: "code",
    redirect_uri: input.redirectUri,
    state,
    scope: "openid profile",
  });

  return {
    sessionId,
    authorizationUrl: `${ONEID_BASE_URL}/oauth/authorize?${params.toString()}`,
  };
}

export async function handleCallback(
  input: HandleOneIdCallbackInput,
  exchangeCode: (code: string) => Promise<OneIdOfficialIdentity>,
): Promise<HandleOneIdCallbackResult> {
  if (!input.code || !input.state) {
    throw new Error("Missing OneID callback parameters");
  }

  let statePayload: { sessionId: string; pinfl: string; kycAssistMode: KycAssistMode };
  try {
    statePayload = JSON.parse(Buffer.from(input.state, "base64url").toString("utf8"));
  } catch {
    throw new Error("Invalid OneID state");
  }

  const official = await exchangeCode(input.code);
  const verifiedAt = new Date().toISOString();

  const session: OneIdSession = {
    sessionId: statePayload.sessionId,
    pinfl: statePayload.pinfl,
    status: "verified",
    kycAssistMode: statePayload.kycAssistMode ?? "self_serve",
    official,
    createdAt: verifiedAt,
    verifiedAt,
  };

  return { session, official };
}
