import type { Context } from "@wrnexus/core";
import type { AuthEngine } from "./engine.ts";
import type { AuthPasskeyHttpOptions } from "./http/index.ts";
import type { AuthSessionVerificationHandler } from "./types.ts";
import { resolveAuthSchemas, type AuthSchemaOverrides, type AuthSchemaSet } from "./validation.ts";

export interface DefaultAuthRouteOptions {
  baseUrl?: string;
  csrf?: boolean;
  passkey?: AuthPasskeyHttpOptions;

  onSignedIn?: (ctx: Context, returnTo?: string) => Response | Promise<Response>;

  onSignedOut?: (ctx: Context) => Response | Promise<Response>;
  sessionCookieName?: string;
  onSessionVerification?: AuthSessionVerificationHandler;
}

interface AuthRuntimeState {
  engine?: AuthEngine;
  schemas: AuthSchemaSet;
  routeOptions: DefaultAuthRouteOptions;
}

/**
 * A Symbol.for registry is used instead of module-local variables.
 *
 * The dev server may import the auth plugin and route modules using
 * different module URLs during HMR. Those modules still execute inside
 * the same JavaScript global realm, so Symbol.for keeps the runtime
 * configuration shared between them.
 */
const AUTH_RUNTIME_STATE_KEY = Symbol.for("@wrnexus/auth:runtime-state:v1");

function runtimeState(): AuthRuntimeState {
  const registry = globalThis as unknown as Record<PropertyKey, unknown>;

  const existing = registry[AUTH_RUNTIME_STATE_KEY] as AuthRuntimeState | undefined;

  if (existing) {
    return existing;
  }

  const created: AuthRuntimeState = {
    schemas: resolveAuthSchemas(),
    routeOptions: {},
  };

  registry[AUTH_RUNTIME_STATE_KEY] = created;

  return created;
}

export function setDefaultAuthEngine(engine: AuthEngine): void {
  runtimeState().engine = engine;
}

/**
 * Clear auth state when an application removes config.auth.engine
 * during development or when another application starts in the
 * same process.
 */
export function clearDefaultAuthEngine(): void {
  delete runtimeState().engine;
}

export function setDefaultAuthSchemas(schemas: AuthSchemaOverrides | AuthSchemaSet = {}): void {
  runtimeState().schemas = resolveAuthSchemas(schemas);
}

export function setDefaultAuthRouteOptions(options: DefaultAuthRouteOptions = {}): void {
  runtimeState().routeOptions = {
    ...options,
  };
}

export function tryGetDefaultAuthEngine(): AuthEngine | undefined {
  return runtimeState().engine;
}

export function getDefaultAuthEngine(): AuthEngine {
  const engine = runtimeState().engine;

  if (!engine) {
    throw new Error(
      "WRN-AUTH-NOT-CONFIGURED: configure auth.engine or call setDefaultAuthEngine(createAuthEngine(...)) at startup",
    );
  }

  return engine;
}

export function getDefaultAuthSchemas(): AuthSchemaSet {
  return runtimeState().schemas;
}

export function getDefaultAuthRouteOptions(): DefaultAuthRouteOptions {
  return runtimeState().routeOptions;
}

export function hasDefaultAuthEngine(): boolean {
  return Boolean(runtimeState().engine);
}
