import type { AuthMode } from "./auth-forms";
import { isRecord } from "./utils";

export type SocialRuntimeProvider<TProvider extends string = string> = {
  provider: TProvider;
  label: string;
  enabledByList: boolean;
  clientIdSet: boolean;
  clientSecretSet: boolean;
  ready: boolean;
};

export type SocialRuntimeParseResult<TProvider extends string = string> = {
  providers: SocialRuntimeProvider<TProvider>[];
  callbackPath: string;
};

export type RuntimeDiagnosticsConfig<TProvider extends string = string> = {
  trustedOriginsRaw: string;
  social: SocialRuntimeParseResult<TProvider>;
};

function normalizeCallbackPath(raw: string | null | undefined): string {
  const trimmed = raw?.trim();
  if (!trimmed) return "/session";
  return trimmed.startsWith("/") ? trimmed : `/${trimmed}`;
}

export function isRuntimeInterferenceError(message: string): boolean {
  const lower = message.toLowerCase();
  return (
    lower.includes("cannot read properties of undefined") &&
    lower.includes("includes")
  );
}

export function parseSocialRuntime<TProvider extends string>(
  payload: unknown,
  supportedProviders: readonly TProvider[],
): SocialRuntimeParseResult<TProvider> {
  if (!isRecord(payload) || !isRecord(payload.social)) {
    return { providers: [], callbackPath: "/session" };
  }

  const callbackPath = normalizeCallbackPath(
    typeof payload.social.callbackPath === "string"
      ? payload.social.callbackPath
      : undefined,
  );

  const providersRaw = Array.isArray(payload.social.providers)
    ? payload.social.providers.filter((entry): entry is Record<string, unknown> =>
        isRecord(entry),
      )
    : [];

  const supported = new Set(supportedProviders);
  const providers: SocialRuntimeProvider<TProvider>[] = [];
  for (const entry of providersRaw) {
    const provider = typeof entry.provider === "string" ? entry.provider : "";
    if (!provider || !supported.has(provider as TProvider)) continue;

    const label = typeof entry.label === "string" ? entry.label : provider;
    const enabledByList = Boolean(entry.enabledByList);
    const clientIdSet = Boolean(entry.clientIdSet);
    const clientSecretSet = Boolean(entry.clientSecretSet);
    const ready = Boolean(entry.ready);
    if (!ready) continue;

    providers.push({
      provider: provider as TProvider,
      label,
      enabledByList,
      clientIdSet,
      clientSecretSet,
      ready,
    });
  }

  return { providers, callbackPath };
}

export function runtimeConfigErrorMessage(payload: unknown, status: number): string {
  if (isRecord(payload) && typeof payload.message === "string") {
    return payload.message;
  }
  return `Runtime config request failed (${status}).`;
}

export function parseRuntimeDiagnosticsConfig<TProvider extends string>(
  payload: unknown,
  supportedProviders: readonly TProvider[],
): RuntimeDiagnosticsConfig<TProvider> {
  const trustedOriginsRaw =
    isRecord(payload) && typeof payload.trustedOriginsRaw === "string"
      ? payload.trustedOriginsRaw
      : "";

  return {
    trustedOriginsRaw,
    social: parseSocialRuntime(payload, supportedProviders),
  };
}

export function buildAuthSubmitFallbackPath(mode: AuthMode): string {
  if (mode === "sign-in") return "/sign-in/email";
  if (mode === "sign-up") return "/sign-up/email";
  return "/forget-password";
}

export function buildAuthSubmitFallbackPayload(
  mode: AuthMode,
  args: {
    email: string;
    password: string;
    name: string;
    origin: string;
  },
): Record<string, unknown> {
  if (mode === "sign-in") {
    return { email: args.email, password: args.password };
  }

  if (mode === "sign-up") {
    return {
      email: args.email,
      password: args.password,
      name: args.name,
    };
  }

  return {
    email: args.email,
    redirectTo: `${args.origin}/reset-password`,
  };
}

export function authSubmitSuccessText(mode: AuthMode): string {
  if (mode === "forgot-password") {
    return "Reset requested. API accepted the request.";
  }
  if (mode === "sign-in") {
    return "Signed in successfully.";
  }
  return "Account created.";
}
