import { Container, getContainer } from "@cloudflare/containers";

const CONTAINER_PORT = 4000;
const CONTAINER_INSTANCE = "default-v9";
const RESERVED_ROOT_PATH_PREFIXES = ["/admin", "/.well-known", "/metrics"];
const RESERVED_ROOT_PATHS = new Set(["/", "/health", "/ping"]);

type WorkerEnv = Env & {
  DATABASE_URL?: string;
  PUBLIC_AUTH_BASE_PATH?: string;
  GITHUB_CALLBACK_URL?: string;
  ATHENA_AUTH_COOKIE_DOMAIN?: string;
  ATHENA_AUTH_SKIP_SCHEMA_PROVISIONING?: string;
};

function valueOrEmpty(value: string | undefined): string {
  return value ?? "";
}

function sanitizeEnvValue(value: string | undefined): string {
  if (!value) {
    return "";
  }

  const trimmed = value.trim();
  const withoutLeadingNoise = trimmed.replace(/^[\u0000-\u001f\u007f-\u009f\ufeff]+/, "");
  const postgresSchemeIndex = withoutLeadingNoise.search(/postgres(?:ql)?:\/\//i);

  if (postgresSchemeIndex > 0) {
    return withoutLeadingNoise.slice(postgresSchemeIndex);
  }

  return withoutLeadingNoise;
}

function cloneRequestOrNull(request: Request): Request | null {
  try {
    return request.clone();
  } catch {
    return null;
  }
}

function normalizeAuthBasePath(basePath: string | undefined): string {
  const trimmed = (basePath ?? "/api/auth").trim();
  if (!trimmed || trimmed === "/") {
    return "/";
  }

  return trimmed.startsWith("/") ? trimmed.replace(/\/+$/, "") : `/${trimmed.replace(/\/+$/, "")}`;
}

function shouldRewriteRequestToAuthBase(pathname: string, authBasePath: string): boolean {
  if (authBasePath === "/" || pathname.startsWith(`${authBasePath}/`) || pathname === authBasePath) {
    return false;
  }
  if (RESERVED_ROOT_PATHS.has(pathname)) {
    return false;
  }

  return !RESERVED_ROOT_PATH_PREFIXES.some((prefix) => pathname === prefix || pathname.startsWith(`${prefix}/`));
}

function containerRequestUrl(request: Request, authBasePath: string): string {
  const url = new URL(request.url);
  if (!shouldRewriteRequestToAuthBase(url.pathname, authBasePath)) {
    return request.url.startsWith("https:") ? request.url.replace("https:", "http:") : request.url;
  }

  url.pathname = `${authBasePath}${url.pathname === "/" ? "" : url.pathname}`;
  if (url.protocol === "https:") {
    url.protocol = "http:";
  }
  return url.toString();
}

function buildContainerEnv(env: WorkerEnv): Record<string, string> {
  return {
    HOST: env.HOST ?? "0.0.0.0",
    PORT: env.PORT ?? String(CONTAINER_PORT),
    AUTH_BASE_PATH: env.AUTH_BASE_PATH ?? "/",
    BASE_URL: env.BASE_URL ?? "https://auth.formations.company",
    ATHENA_AUTH_COOKIE_DOMAIN: valueOrEmpty(env.ATHENA_AUTH_COOKIE_DOMAIN),
    RUST_LOG: env.RUST_LOG ?? "info",
    PASSKEY_ALLOW_INSECURE: env.PASSKEY_ALLOW_INSECURE ?? "false",
    PASSKEY_ORIGIN: env.PASSKEY_ORIGIN ?? env.BASE_URL ?? "",
    PASSKEY_RP_ID: env.PASSKEY_RP_ID ?? "auth.formations.company",
    PASSKEY_RP_NAME: env.PASSKEY_RP_NAME ?? "Suits Formations",
    TRUSTED_ORIGINS: env.TRUSTED_ORIGINS ?? "",
    SMTP_HOST: valueOrEmpty(env.SMTP_HOST),
    SMTP_PORT: env.SMTP_PORT ?? "587",
    SMTP_FROM_ADDRESS: valueOrEmpty(env.SMTP_FROM_ADDRESS),
    SMTP_FROM_NAME: valueOrEmpty(env.SMTP_FROM_NAME),
    GOOGLE_CLIENT_ID: valueOrEmpty(env.GOOGLE_CLIENT_ID),
    GOOGLE_CLIENT_SECRET: valueOrEmpty(env.GOOGLE_CLIENT_SECRET),
    APPLE_CLIENT_ID: valueOrEmpty(env.APPLE_CLIENT_ID),
    APPLE_CLIENT_SECRET: valueOrEmpty(env.APPLE_CLIENT_SECRET),
    MICROSOFT_CLIENT_ID: valueOrEmpty(env.MICROSOFT_CLIENT_ID),
    MICROSOFT_SECRET: valueOrEmpty(env.MICROSOFT_SECRET),
    GITHUB_CLIENT_ID: valueOrEmpty(env.GITHUB_CLIENT_ID),
    GITHUB_CLIENT_SECRET: valueOrEmpty(env.GITHUB_CLIENT_SECRET),
    PUBLIC_AUTH_BASE_PATH: valueOrEmpty(env.PUBLIC_AUTH_BASE_PATH),
    GITHUB_CALLBACK_URL: valueOrEmpty(env.GITHUB_CALLBACK_URL),
    DATABASE_URL: sanitizeEnvValue(env.DATABASE_URL),
    DATABASE_KEY: valueOrEmpty(env.DATABASE_KEY),
    JWT_SECRET: valueOrEmpty(env.JWT_SECRET),
    ATHENA_AUTH_SKIP_SCHEMA_PROVISIONING: valueOrEmpty(
      env.ATHENA_AUTH_SKIP_SCHEMA_PROVISIONING,
    ),
    SMTP_USER: valueOrEmpty(env.SMTP_USER),
    SMTP_PASS: valueOrEmpty(env.SMTP_PASS),
  };
}

export class AthenaAuthContainer extends Container<WorkerEnv> {
  defaultPort = CONTAINER_PORT;
  requiredPorts = [CONTAINER_PORT];
  pingEndpoint = "localhost/ping";
  sleepAfter = "30m";

  constructor(ctx: DurableObjectState<{}>, env: WorkerEnv) {
    super(ctx, env);
    this.syncContainerEnv();
  }

  private syncContainerEnv(): void {
    this.envVars = buildContainerEnv(this.env);
  }

  private currentRequestTargetsKnownRunningContainer(
    state: Awaited<ReturnType<Container<WorkerEnv>["getState"]>>,
  ): boolean {
    return !this.isContainerRuntimeRunning() && (state.status === "healthy" || state.status === "running");
  }

  private isContainerRuntimeRunning(): boolean {
    return Boolean((this as unknown as { container?: { running?: boolean } }).container?.running);
  }

  private async proxyDirectlyToContainer(request: Request): Promise<Response> {
    const port = this.defaultPort ?? CONTAINER_PORT;
    const internal = this as unknown as {
      container: {
        getTcpPort(port: number): {
          fetch(input: string, init: Request): Promise<Response>;
        };
      };
    };
    const tcpPort = internal.container.getTcpPort(port);
    const containerUrl = containerRequestUrl(
      request,
      normalizeAuthBasePath(this.env.AUTH_BASE_PATH),
    );

    this.renewActivityTimeout();
    return await tcpPort.fetch(containerUrl, request);
  }

  private isAlreadyRunningStartError(responseBody: string): boolean {
    return responseBody.includes("start() cannot be called on a container that is already running.");
  }

  override async fetch(request: Request): Promise<Response> {
    this.syncContainerEnv();
    const retryRequest = cloneRequestOrNull(request);
    const state = await this.getState();

    if (this.currentRequestTargetsKnownRunningContainer(state)) {
      try {
        console.warn("Container attach race detected; proxying directly to the existing instance");
        return await this.proxyDirectlyToContainer(request);
      } catch (error) {
        console.warn("Direct container attach failed; falling back to managed startup", error);
      }
    }

    try {
      await this.startAndWaitForPorts({
        ports: CONTAINER_PORT,
        cancellationOptions: {
          abort: request.signal,
          instanceGetTimeoutMS: 60_000,
          portReadyTimeoutMS: 60_000,
          waitInterval: 1_000,
        },
      });
      return await this.proxyDirectlyToContainer(request);
    } catch (error) {
      const message = error instanceof Error ? error.message : String(error);

      if (retryRequest !== null && this.isAlreadyRunningStartError(message)) {
        try {
          console.warn("Container runtime reported an already-running instance; retrying via direct proxy");
          return await this.proxyDirectlyToContainer(retryRequest);
        } catch (retryError) {
          console.error("Direct proxy retry after container start race failed", retryError);
        }
      }

      return new Response(`Failed to start container: ${message}`, { status: 500 });
    }
  }

  onStart(): void {
    console.log("Athena Auth container started", {
      port: this.defaultPort,
      database: this.envVars?.DATABASE_URL ? "direct-postgres" : "missing-database-url",
      github: this.envVars?.GITHUB_CLIENT_ID ? "configured" : "missing-github-client-id",
    });
  }

  onStop(params: { exitCode: number; reason: string }): void {
    console.error("Athena Auth container stopped", params);
  }

  onError(error: unknown): never {
    console.error("Athena Auth container error", error);
    throw error;
  }
}

function missingContainerConfig(env: WorkerEnv): string | null {
  if (!env.DATABASE_URL?.trim()) {
    return "DATABASE_URL is not configured. Set it via wrangler secret put DATABASE_URL (or .dev.vars for local dev).";
  }
  if (!env.JWT_SECRET?.trim()) {
    return "JWT_SECRET is not configured. Set it via wrangler secret put JWT_SECRET (or .dev.vars for local dev).";
  }
  return null;
}

export default {
  async fetch(request: Request, workerEnv: WorkerEnv): Promise<Response> {
    const configError = missingContainerConfig(workerEnv);
    if (configError) {
      return new Response(configError, { status: 500 });
    }

    return getContainer(workerEnv.ATHENA_AUTH_CONTAINER, CONTAINER_INSTANCE).fetch(request);
  },
};
