"use client";

import { useEffect, useMemo, useState } from "react";
import { SharedBackButton } from "./shared-back-button";
import { TrustedOriginDebugSection } from "./trusted-origin-debug-section";
import { Badge } from "./ui/badge";
import { Button } from "./ui/button";
import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "./ui/card";

type JsonRecord = Record<string, unknown>;

function asRecord(value: unknown): JsonRecord | null {
  return typeof value === "object" && value !== null ? (value as JsonRecord) : null;
}

function asString(value: unknown): string | null {
  return typeof value === "string" ? value : null;
}

function asBoolean(value: unknown): boolean | null {
  return typeof value === "boolean" ? value : null;
}

function asStringArray(value: unknown): string[] {
  if (!Array.isArray(value)) return [];
  return value.filter((entry): entry is string => typeof entry === "string");
}

function asRecordArray(value: unknown): JsonRecord[] {
  if (!Array.isArray(value)) return [];
  return value
    .map((entry) => asRecord(entry))
    .filter((entry): entry is JsonRecord => entry !== null);
}

function statusVariant(status: string): "default" | "secondary" | "success" | "warning" | "destructive" {
  const normalized = status.toLowerCase();
  if (normalized.includes("ready") || normalized === "ok") return "success";
  if (normalized.includes("missing") || normalized.includes("error")) return "destructive";
  if (normalized.includes("outside") || normalized.includes("mismatch")) return "warning";
  return "secondary";
}

export function SchemaDebugView() {
  const [payload, setPayload] = useState<JsonRecord | null>(null);
  const [proxyOriginDebugPayload, setProxyOriginDebugPayload] = useState<JsonRecord | null>(null);
  const [loading, setLoading] = useState(false);
  const [error, setError] = useState<string | null>(null);
  const [lastLoadedAt, setLastLoadedAt] = useState<string | null>(null);

  const load = async () => {
    setLoading(true);
    setError(null);

    try {
      const [schemaResult, diagnosticsResult] = await Promise.allSettled([
        fetch("/api/auth/debug/schema", {
          method: "GET",
          cache: "no-store",
        }),
        fetch("/api/auth/diagnostics", {
          method: "GET",
          cache: "no-store",
        }),
      ]);

      if (diagnosticsResult.status === "fulfilled") {
        const diagnosticsJson = (await diagnosticsResult.value.json().catch(() => ({}))) as unknown;
        const diagnosticsPayload = asRecord(diagnosticsJson);
        setProxyOriginDebugPayload(asRecord(diagnosticsPayload?.proxyOriginDebug));
      } else {
        setProxyOriginDebugPayload(null);
      }

      if (schemaResult.status !== "fulfilled") {
        setPayload(null);
        setError("Schema debug request failed.");
        return;
      }

      const response = schemaResult.value;
      const json = (await response.json().catch(() => ({}))) as unknown;
      const parsed = asRecord(json);

      if (!response.ok) {
        const message =
          parsed && asString(parsed.message)
            ? asString(parsed.message)
            : `Schema debug request failed (${response.status}).`;
        setPayload(parsed);
        setError(message ?? "Schema debug request failed.");
        return;
      }

      setPayload(parsed);
      setLastLoadedAt(new Date().toISOString());
    } catch (loadError) {
      const message =
        loadError instanceof Error ? loadError.message : "Schema debug request failed.";
      setPayload(null);
      setError(message);
    } finally {
      setLoading(false);
    }
  };

  useEffect(() => {
    void load();

    const onVisible = () => {
      if (!document.hidden) {
        void load();
      }
    };
    const interval = window.setInterval(() => {
      void load();
    }, 30000);

    document.addEventListener("visibilitychange", onVisible);
    return () => {
      window.clearInterval(interval);
      document.removeEventListener("visibilitychange", onVisible);
    };
  }, []);

  const runtime = useMemo(() => asRecord(payload?.runtime), [payload]);
  const request = useMemo(() => asRecord(payload?.request), [payload]);
  const currentProbe = useMemo(
    () => asRecord(payload?.current_tenant_probe),
    [payload],
  );
  const searchPath = useMemo(
    () => asRecord(currentProbe?.search_path),
    [currentProbe],
  );
  const tableAliasConfig = useMemo(() => {
    const config = asRecord(runtime?.table_alias_config);
    return asRecordArray(config?.entries);
  }, [runtime]);

  const resolutionStatus = asString(request?.resolution_status) ?? "unknown";
  const probeStatus = asString(currentProbe?.status) ?? "unknown";
  const tableRows = asRecordArray(currentProbe?.table_resolution);
  const mappingNote =
    asString(runtime?.mapping_application_note) ??
    "No mapping note returned by server.";

  return (
    <main className="mx-auto w-full max-w-7xl px-4 pb-10 pt-8">
      <div className="mb-4 flex items-center justify-between gap-3">
        <SharedBackButton fallbackHref="/session" />
        <Badge variant="secondary">Schema debugger</Badge>
      </div>

      <Card>
        <CardHeader>
          <CardTitle>Schema and table mapping debugger</CardTitle>
          <CardDescription>
            Live diagnostics from <code>/api/auth/debug/schema</code> including tenant resolution,
            effective search path, mapping target tables, and runtime lookup status.
          </CardDescription>
        </CardHeader>
        <CardContent className="grid gap-4">
          <div className="flex flex-wrap items-center gap-2 text-xs">
            <Badge variant={loading ? "secondary" : "success"}>
              {loading ? "loading" : "loaded"}
            </Badge>
            <Badge variant={statusVariant(resolutionStatus)}>
              request: {resolutionStatus}
            </Badge>
            <Badge variant={statusVariant(probeStatus)}>
              probe: {probeStatus}
            </Badge>
            <Badge variant={asBoolean(runtime?.multitenancy_enabled) ? "success" : "secondary"}>
              multitenancy: {asBoolean(runtime?.multitenancy_enabled) ? "enabled" : "single-tenant"}
            </Badge>
            <Badge variant="secondary">auto refresh: 30s + focus</Badge>
          </div>

          <div className="flex flex-wrap gap-2">
            <Button variant="secondary" onClick={() => void load()} disabled={loading}>
              {loading ? "Refreshing..." : "Refresh now"}
            </Button>
          </div>

          {error ? (
            <p className="rounded-md border border-red-200 bg-red-50 px-3 py-2 text-sm text-red-700">
              {error}
            </p>
          ) : null}

          <TrustedOriginDebugSection
            value={
              payload?.origin_rejection_debug ??
              proxyOriginDebugPayload ??
              payload?.proxy_origin_debug
            }
          />

          <div className="grid gap-2 rounded-xl border border-slate-200 bg-white p-4 text-sm">
            <div>
              <strong>Generated at:</strong>{" "}
              {asString(payload?.generated_at) ?? "(not returned)"}
            </div>
            <div>
              <strong>Last loaded in demo:</strong>{" "}
              {lastLoadedAt ?? "(not loaded yet)"}
            </div>
            <div>
              <strong>Tenant header:</strong>{" "}
              {asString(runtime?.tenant_header_name) ?? "(not returned)"}
            </div>
            <div>
              <strong>Configured header value:</strong>{" "}
              {asString(request?.configured_header_value) ?? "(empty)"}
            </div>
            <div>
              <strong>Resolved tenant:</strong>{" "}
              {asString(request?.resolved_tenant) ?? "(none)"}
            </div>
            <div>
              <strong>Probed tenant:</strong>{" "}
              {asString(currentProbe?.tenant_id) ?? "(none)"}
            </div>
            <div>
              <strong>Mapping mode:</strong>{" "}
              {asString(runtime?.mapping_application_mode) ?? "(not returned)"}
            </div>
            <div className="rounded-md border border-slate-200 bg-slate-50 px-3 py-2 text-xs text-slate-700">
              {mappingNote}
            </div>
          </div>

          <div className="grid gap-2 rounded-xl border border-slate-200 bg-white p-4 text-sm">
            <h3 className="text-sm font-semibold text-slate-900">Search path</h3>
            <div>
              <strong>Configured SQL fragment:</strong>{" "}
              {asString(searchPath?.configured_sql_fragment) ?? "(default)"}
            </div>
            <div>
              <strong>Runtime current schema:</strong>{" "}
              {asString(searchPath?.runtime_current_schema) ?? "(unknown)"}
            </div>
            <div>
              <strong>Runtime setting search_path:</strong>{" "}
              {asString(searchPath?.runtime_setting_search_path) ?? "(unknown)"}
            </div>
            <div>
              <strong>Runtime effective schemas:</strong>{" "}
              {asStringArray(searchPath?.runtime_effective_schemas).join(", ") || "(none)"}
            </div>
          </div>

          <section className="rounded-xl border border-slate-200 bg-white p-4">
            <h3 className="text-sm font-semibold text-slate-900">
              Default table alias config
            </h3>
            <p className="mt-1 text-xs text-slate-500">
              Primary runtime logical table names plus automatic secondary variants (singular/plural).
            </p>
            <div className="mt-3 overflow-x-auto">
              <table className="min-w-full table-fixed border-collapse text-xs">
                <thead>
                  <tr className="bg-slate-100 text-left text-slate-700">
                    <th className="border border-slate-200 px-2 py-2">Primary table</th>
                    <th className="border border-slate-200 px-2 py-2">Secondary table</th>
                    <th className="border border-slate-200 px-2 py-2">Primary is plural</th>
                    <th className="border border-slate-200 px-2 py-2">Secondary is plural</th>
                  </tr>
                </thead>
                <tbody>
                  {tableAliasConfig.length === 0 ? (
                    <tr>
                      <td className="border border-slate-200 px-2 py-3 text-slate-500" colSpan={4}>
                        No alias config entries returned.
                      </td>
                    </tr>
                  ) : (
                    tableAliasConfig.map((entry, idx) => {
                      const primaryPlural = asBoolean(entry.primary_is_plural);
                      const secondaryPlural = asBoolean(entry.secondary_is_plural);
                      return (
                        <tr key={`${asString(entry.primary_table) ?? "alias"}-${idx}`}>
                          <td className="border border-slate-200 px-2 py-2 align-top">
                            {asString(entry.primary_table) ?? "-"}
                          </td>
                          <td className="border border-slate-200 px-2 py-2 align-top">
                            {asString(entry.secondary_table) ?? "(none)"}
                          </td>
                          <td className="border border-slate-200 px-2 py-2 align-top">
                            <Badge
                              variant={
                                primaryPlural === null
                                  ? "secondary"
                                  : primaryPlural
                                    ? "success"
                                    : "warning"
                              }
                            >
                              {primaryPlural === null ? "n/a" : String(primaryPlural)}
                            </Badge>
                          </td>
                          <td className="border border-slate-200 px-2 py-2 align-top">
                            <Badge
                              variant={
                                secondaryPlural === null
                                  ? "secondary"
                                  : secondaryPlural
                                    ? "success"
                                    : "warning"
                              }
                            >
                              {secondaryPlural === null ? "n/a" : String(secondaryPlural)}
                            </Badge>
                          </td>
                        </tr>
                      );
                    })
                  )}
                </tbody>
              </table>
            </div>
          </section>

          <section className="rounded-xl border border-slate-200 bg-white p-4">
            <h3 className="text-sm font-semibold text-slate-900">Table resolution</h3>
            <p className="mt-1 text-xs text-slate-500">
              <code>runtime_lookup_table</code> is what Athena Auth queries today.{" "}
              <code>configured_mapped_table</code> is your mapping target for debugging comparison.
            </p>

            <div className="mt-3 overflow-x-auto">
              <table className="min-w-full table-fixed border-collapse text-xs">
                <thead>
                  <tr className="bg-slate-100 text-left text-slate-700">
                    <th className="border border-slate-200 px-2 py-2">Logical</th>
                    <th className="border border-slate-200 px-2 py-2">Runtime lookup</th>
                    <th className="border border-slate-200 px-2 py-2">Mapped target</th>
                    <th className="border border-slate-200 px-2 py-2">Runtime status (boolean)</th>
                    <th className="border border-slate-200 px-2 py-2">Mapped status (boolean)</th>
                    <th className="border border-slate-200 px-2 py-2">Status</th>
                  </tr>
                </thead>
                <tbody>
                  {tableRows.length === 0 ? (
                    <tr>
                      <td className="border border-slate-200 px-2 py-3 text-slate-500" colSpan={6}>
                        No table resolution rows returned.
                      </td>
                    </tr>
                  ) : (
                    tableRows.map((row, idx) => {
                      const runtimeStatus = asRecord(row.runtime_status);
                      const mappedStatus = asRecord(row.mapped_status);
                      const overall = asString(row.overall_status) ?? "unknown";
                      const runtimeLookupSecondary = asString(
                        row.runtime_secondary_lookup_table,
                      );
                      const mappedLookupSecondary = asString(
                        row.configured_secondary_mapped_table,
                      );
                      const runtimeFoundPrimary = asBoolean(
                        runtimeStatus?.found_in_effective_search_path_primary,
                      );
                      const runtimeFoundSecondary = asBoolean(
                        runtimeStatus?.found_in_effective_search_path_secondary,
                      );
                      const runtimeFoundAny = asBoolean(
                        runtimeStatus?.found_in_effective_search_path_any,
                      );
                      const mappedFoundPrimary = asBoolean(
                        mappedStatus?.found_in_effective_search_path_primary,
                      );
                      const mappedFoundSecondary = asBoolean(
                        mappedStatus?.found_in_effective_search_path_secondary,
                      );
                      const mappedFoundAny = asBoolean(
                        mappedStatus?.found_in_effective_search_path_any,
                      );
                      const runtimeFound = asBoolean(
                        runtimeStatus?.found_in_effective_search_path,
                      );
                      const mappedFound = asBoolean(
                        mappedStatus?.found_in_effective_search_path,
                      );

                      return (
                        <tr key={`${asString(row.logical_table) ?? "row"}-${idx}`}>
                          <td className="border border-slate-200 px-2 py-2 align-top">
                            {asString(row.logical_table) ?? "-"}
                          </td>
                          <td className="border border-slate-200 px-2 py-2 align-top">
                            <div className="grid gap-1">
                              <div>{asString(row.runtime_lookup_table) ?? "-"}</div>
                              <div className="text-[11px] text-slate-500">
                                secondary: {runtimeLookupSecondary ?? "(none)"}
                              </div>
                            </div>
                          </td>
                          <td className="border border-slate-200 px-2 py-2 align-top">
                            <div className="grid gap-1">
                              <div>{asString(row.configured_mapped_table) ?? "-"}</div>
                              <div className="text-[11px] text-slate-500">
                                secondary: {mappedLookupSecondary ?? "(none)"}
                              </div>
                            </div>
                          </td>
                          <td className="border border-slate-200 px-2 py-2 align-top">
                            <div className="grid gap-1">
                              <Badge
                                variant={
                                  runtimeFoundAny === null
                                    ? runtimeFound
                                      ? "success"
                                      : "destructive"
                                    : runtimeFoundAny
                                      ? "success"
                                      : "destructive"
                                }
                              >
                                any:{" "}
                                {runtimeFoundAny === null
                                  ? runtimeFound === null
                                    ? "n/a"
                                    : String(runtimeFound)
                                  : String(runtimeFoundAny)}
                              </Badge>
                              <div className="text-[11px] text-slate-500">
                                primary: {runtimeFoundPrimary === null ? "n/a" : String(runtimeFoundPrimary)}
                              </div>
                              <div className="text-[11px] text-slate-500">
                                secondary:{" "}
                                {runtimeFoundSecondary === null ? "n/a" : String(runtimeFoundSecondary)}
                              </div>
                            </div>
                          </td>
                          <td className="border border-slate-200 px-2 py-2 align-top">
                            <div className="grid gap-1">
                              <Badge
                                variant={
                                  mappedFoundAny === null
                                    ? mappedFound === null
                                      ? "secondary"
                                      : mappedFound
                                        ? "success"
                                        : "warning"
                                    : mappedFoundAny
                                      ? "success"
                                      : "warning"
                                }
                              >
                                any:{" "}
                                {mappedFoundAny === null
                                  ? mappedFound === null
                                    ? "n/a"
                                    : String(mappedFound)
                                  : String(mappedFoundAny)}
                              </Badge>
                              <div className="text-[11px] text-slate-500">
                                primary: {mappedFoundPrimary === null ? "n/a" : String(mappedFoundPrimary)}
                              </div>
                              <div className="text-[11px] text-slate-500">
                                secondary:{" "}
                                {mappedFoundSecondary === null ? "n/a" : String(mappedFoundSecondary)}
                              </div>
                            </div>
                          </td>
                          <td className="border border-slate-200 px-2 py-2 align-top">
                            <div className="grid gap-1">
                              <Badge variant={statusVariant(overall)}>{overall}</Badge>
                              <div className="text-[11px] text-slate-500">
                                {asString(row.note) ?? ""}
                              </div>
                            </div>
                          </td>
                        </tr>
                      );
                    })
                  )}
                </tbody>
              </table>
            </div>
          </section>

          <details className="rounded-xl border border-slate-200 bg-slate-50 p-4">
            <summary className="cursor-pointer text-sm font-semibold text-slate-900">
              Raw payload
            </summary>
            <pre className="mt-3 max-h-[420px] overflow-auto rounded-lg bg-slate-950 p-3 text-xs text-slate-100">
              {JSON.stringify(payload, null, 2)}
            </pre>
          </details>
        </CardContent>
      </Card>
    </main>
  );
}
