export const SOCIAL_PROVIDER_IDS = [
  "google",
  "apple",
  "github",
  "discord",
  "cloudflare",
] as const;

export type SocialProviderId = (typeof SOCIAL_PROVIDER_IDS)[number];

export type SocialProviderConfig = {
  provider: SocialProviderId;
  label: string;
  enabledByList: boolean;
  clientIdSet: boolean;
  clientSecretSet: boolean;
  ready: boolean;
};

export type SocialAuthDiagnostics = {
  configuredProvidersRaw: string;
  configuredProviders: SocialProviderId[];
  unknownProviders: string[];
  callbackPath: string;
  providers: SocialProviderConfig[];
  readyProviders: SocialProviderId[];
};

type ProviderEnvConfig = {
  label: string;
  clientIdKeys: string[];
  clientSecretKeys: string[];
};

const PROVIDER_ENV: Record<SocialProviderId, ProviderEnvConfig> = {
  google: {
    label: "Google",
    clientIdKeys: ["GOOGLE_CLIENT_ID", "AUTH_GOOGLE_CLIENT_ID"],
    clientSecretKeys: ["GOOGLE_CLIENT_SECRET", "AUTH_GOOGLE_CLIENT_SECRET"],
  },
  apple: {
    label: "Apple",
    clientIdKeys: ["APPLE_CLIENT_ID", "AUTH_APPLE_CLIENT_ID"],
    clientSecretKeys: ["APPLE_CLIENT_SECRET", "AUTH_APPLE_CLIENT_SECRET"],
  },
  github: {
    label: "GitHub",
    clientIdKeys: ["GITHUB_CLIENT_ID", "AUTH_GITHUB_CLIENT_ID"],
    clientSecretKeys: ["GITHUB_CLIENT_SECRET", "AUTH_GITHUB_CLIENT_SECRET"],
  },
  discord: {
    label: "Discord",
    clientIdKeys: ["DISCORD_CLIENT_ID", "AUTH_DISCORD_CLIENT_ID"],
    clientSecretKeys: ["DISCORD_CLIENT_SECRET", "AUTH_DISCORD_CLIENT_SECRET"],
  },
  cloudflare: {
    label: "Cloudflare",
    clientIdKeys: [
      "CLOUDFLARE_CLIENT_ID",
      "CLOUDFLARE_OAUTH_CLIENT_ID",
      "AUTH_CLOUDFLARE_CLIENT_ID",
    ],
    clientSecretKeys: [
      "CLOUDFLARE_CLIENT_SECRET",
      "CLOUDFLARE_OAUTH_CLIENT_SECRET",
      "CLOUDFLARE_OAUTH_CLIENT_PUBLISHER",
      "cloudflare_oauth_client_publisher",
      "AUTH_CLOUDFLARE_CLIENT_SECRET",
    ],
  },
};

function hasValue(value: string | undefined): boolean {
  return typeof value === "string" && value.trim().length > 0;
}

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

function parseConfiguredProviders(raw: string | undefined): {
  configured: SocialProviderId[];
  configuredSet: Set<SocialProviderId>;
  unknown: string[];
  normalizedRaw: string;
} {
  const normalizedRaw = raw?.trim() ?? "";
  const configuredSet = new Set<SocialProviderId>();
  const unknown: string[] = [];

  for (const entry of normalizedRaw.split(",")) {
    const value = entry.trim().toLowerCase();
    if (!value) continue;
    if (
      SOCIAL_PROVIDER_IDS.includes(value as SocialProviderId) &&
      !configuredSet.has(value as SocialProviderId)
    ) {
      configuredSet.add(value as SocialProviderId);
      continue;
    }
    if (!unknown.includes(value)) {
      unknown.push(value);
    }
  }

  return {
    configured: [...configuredSet],
    configuredSet,
    unknown,
    normalizedRaw,
  };
}

function isProviderReady(
  provider: SocialProviderId,
  configuredSet: Set<SocialProviderId>,
): SocialProviderConfig {
  const envConfig = PROVIDER_ENV[provider];
  const clientIdSet = envConfig.clientIdKeys.some((key) => hasValue(process.env[key]));
  const clientSecretSet = envConfig.clientSecretKeys.some((key) =>
    hasValue(process.env[key]),
  );
  const enabledByList = configuredSet.has(provider);
  const ready = enabledByList && clientIdSet && clientSecretSet;

  return {
    provider,
    label: envConfig.label,
    enabledByList,
    clientIdSet,
    clientSecretSet,
    ready,
  };
}

export function getSocialAuthDiagnostics(): SocialAuthDiagnostics {
  const parsed = parseConfiguredProviders(process.env.NEXT_PUBLIC_AUTH_SOCIAL_PROVIDERS);
  const callbackPath = normalizeCallbackPath(
    process.env.NEXT_PUBLIC_AUTH_SOCIAL_CALLBACK_PATH,
  );
  const providers = SOCIAL_PROVIDER_IDS.map((provider) =>
    isProviderReady(provider, parsed.configuredSet),
  );

  return {
    configuredProvidersRaw: parsed.normalizedRaw,
    configuredProviders: parsed.configured,
    unknownProviders: parsed.unknown,
    callbackPath,
    providers,
    readyProviders: providers.filter((provider) => provider.ready).map((provider) => provider.provider),
  };
}

