import Link from "next/link";
import { createClient } from "@/lib/supabase/server";
import { PageHeader } from "@/components/layout/page-header";
import { Card } from "@/components/ui/card";
import { Badge } from "@/components/ui/badge";
import { Button } from "@/components/ui/button";
import {
  Table,
  TableBody,
  TableCell,
  TableHead,
  TableHeader,
  TableRow,
} from "@/components/ui/table";
import { AuditFilters } from "./audit-filters";

const PAGE_SIZE = 50;

type AuditAction = "insert" | "update" | "delete" | string;

interface AuditRow {
  id: number;
  table_name: string | null;
  row_id: string | null;
  action: AuditAction;
  actor_id: string | null;
  branch_id: string | null;
  before: Record<string, unknown> | null;
  after: Record<string, unknown> | null;
  ip: string | null;
  user_agent: string | null;
  created_at: string;
  actor?: { full_name: string | null; email: string | null } | null;
}

const ACTION_BADGE: Record<string, string> = {
  insert: "bg-emerald-100 text-emerald-700",
  update: "bg-amber-100 text-amber-700",
  delete: "bg-red-100 text-red-700",
};

/** Render a jsonb value compactly for the changes summary. */
function fmt(value: unknown): string {
  if (value === null || value === undefined) return "∅";
  if (typeof value === "object") {
    try {
      const s = JSON.stringify(value);
      return s.length > 40 ? s.slice(0, 37) + "…" : s;
    } catch {
      return "[object]";
    }
  }
  const s = String(value);
  return s.length > 40 ? s.slice(0, 37) + "…" : s;
}

/**
 * Summarize a before/after jsonb diff into a short human string.
 * - insert  -> "created" + a couple of seeded fields
 * - delete  -> "deleted"
 * - update  -> "key: old → new" for up to 3 changed keys, then "+N more"
 */
function summarizeChanges(row: AuditRow): string {
  const action = row.action;
  const before = (row.before ?? {}) as Record<string, unknown>;
  const after = (row.after ?? {}) as Record<string, unknown>;

  if (action === "delete") return "deleted";

  if (action === "insert") {
    return "created";
  }

  // update (and any other action): compute changed keys.
  const keys = new Set<string>([
    ...Object.keys(before),
    ...Object.keys(after),
  ]);

  const changed: string[] = [];
  for (const key of keys) {
    const b = before[key];
    const a = after[key];
    if (JSON.stringify(b) !== JSON.stringify(a)) {
      changed.push(`${key}: ${fmt(b)} → ${fmt(a)}`);
    }
  }

  if (changed.length === 0) return "no field changes";

  const shown = changed.slice(0, 3).join(", ");
  const extra = changed.length - 3;
  return extra > 0 ? `${shown} +${extra} more` : shown;
}

function actorLabel(row: AuditRow): string {
  if (row.actor?.full_name) return row.actor.full_name;
  if (row.actor?.email) return row.actor.email;
  if (row.actor_id) return row.actor_id.slice(0, 8);
  return "System";
}

export default async function AuditLogPage({
  searchParams,
}: {
  searchParams: Promise<{ table?: string; action?: string; page?: string }>;
}) {
  const sp = await searchParams;
  const supabase = await createClient();

  const page = Math.max(1, parseInt(sp.page ?? "1", 10) || 1);
  const from = (page - 1) * PAGE_SIZE;
  const to = from + PAGE_SIZE - 1;

  // Try embedding the actor via the FK alias; fall back to a separate fetch.
  let query = supabase
    .from("audit_log")
    .select(
      "id, table_name, row_id, action, actor_id, branch_id, before, after, ip, user_agent, created_at, actor:users!audit_log_actor_id_fkey(full_name, email)",
      { count: "exact" },
    )
    .order("created_at", { ascending: false })
    .range(from, to);

  if (sp.table) query = query.eq("table_name", sp.table);
  if (sp.action) query = query.eq("action", sp.action);

  const initial = await query;
  let data: unknown = initial.data;
  let count = initial.count;
  let error = initial.error;

  // If the FK embed alias is wrong, retry without the embed and resolve names.
  if (error) {
    let fallback = supabase
      .from("audit_log")
      .select(
        "id, table_name, row_id, action, actor_id, branch_id, before, after, ip, user_agent, created_at",
        { count: "exact" },
      )
      .order("created_at", { ascending: false })
      .range(from, to);

    if (sp.table) fallback = fallback.eq("table_name", sp.table);
    if (sp.action) fallback = fallback.eq("action", sp.action);

    const res = await fallback;
    data = res.data;
    count = res.count;
    error = res.error;

    const fbRows = (data as unknown as AuditRow[]) ?? [];
    if (!error && fbRows.length > 0) {
      const actorIds = Array.from(
        new Set(
          fbRows
            .map((r) => r.actor_id)
            .filter((v): v is string => Boolean(v)),
        ),
      );
      if (actorIds.length > 0) {
        const { data: users } = await supabase
          .from("users")
          .select("id, full_name, email")
          .in("id", actorIds);
        const byId = new Map(
          (users ?? []).map((u: { id: string; full_name: string | null; email: string | null }) => [
            u.id,
            { full_name: u.full_name, email: u.email },
          ]),
        );
        for (const r of fbRows) {
          r.actor = r.actor_id ? byId.get(r.actor_id) ?? null : null;
        }
      }
    }
  }

  const rows = (data as unknown as AuditRow[]) ?? [];
  const total = count ?? 0;
  const totalPages = Math.max(1, Math.ceil(total / PAGE_SIZE));
  const hasPrev = page > 1;
  const hasNext = page < totalPages;

  // Preserve filters when building pagination links.
  const buildHref = (targetPage: number) => {
    const params = new URLSearchParams();
    if (sp.table) params.set("table", sp.table);
    if (sp.action) params.set("action", sp.action);
    params.set("page", String(targetPage));
    return `?${params.toString()}`;
  };

  return (
    <div>
      <PageHeader title="Audit Log" breadcrumb="Settings / Audit Log" />

      <AuditFilters />

      <Card className="p-0">
        <Table>
          <TableHeader>
            <TableRow>
              <TableHead className="w-44">When</TableHead>
              <TableHead>Actor</TableHead>
              <TableHead className="w-24">Action</TableHead>
              <TableHead>Table</TableHead>
              <TableHead className="w-28">Row</TableHead>
              <TableHead>Changes</TableHead>
            </TableRow>
          </TableHeader>
          <TableBody>
            {error ? (
              <TableRow>
                <TableCell
                  colSpan={6}
                  className="py-10 text-center text-destructive"
                >
                  Failed to load audit log.
                </TableCell>
              </TableRow>
            ) : rows.length === 0 ? (
              <TableRow>
                <TableCell
                  colSpan={6}
                  className="py-10 text-center text-muted-foreground"
                >
                  No audit entries.
                </TableCell>
              </TableRow>
            ) : (
              rows.map((r) => (
                <TableRow key={r.id}>
                  <TableCell className="whitespace-nowrap text-muted-foreground">
                    {new Date(r.created_at).toLocaleString()}
                  </TableCell>
                  <TableCell className="font-medium">{actorLabel(r)}</TableCell>
                  <TableCell>
                    <Badge
                      className={
                        ACTION_BADGE[r.action] ?? "bg-muted text-foreground"
                      }
                    >
                      {r.action}
                    </Badge>
                  </TableCell>
                  <TableCell className="text-brand-navy">
                    {r.table_name ?? "—"}
                  </TableCell>
                  <TableCell className="font-mono text-xs text-muted-foreground">
                    {r.row_id ? r.row_id.slice(0, 8) : "—"}
                  </TableCell>
                  <TableCell className="text-sm text-muted-foreground">
                    {summarizeChanges(r)}
                  </TableCell>
                </TableRow>
              ))
            )}
          </TableBody>
        </Table>
      </Card>

      <div className="mt-4 flex items-center justify-between">
        <p className="text-sm text-muted-foreground">
          {total > 0
            ? `Showing ${from + 1}–${Math.min(to + 1, total)} of ${total}`
            : "0 entries"}
          {" · "}Page {page} of {totalPages}
        </p>
        <div className="flex gap-2">
          <Button
            asChild={hasPrev}
            variant="outline"
            size="sm"
            disabled={!hasPrev}
          >
            {hasPrev ? (
              <Link href={buildHref(page - 1)}>Previous</Link>
            ) : (
              <span>Previous</span>
            )}
          </Button>
          <Button
            asChild={hasNext}
            variant="outline"
            size="sm"
            disabled={!hasNext}
          >
            {hasNext ? (
              <Link href={buildHref(page + 1)}>Next</Link>
            ) : (
              <span>Next</span>
            )}
          </Button>
        </div>
      </div>
    </div>
  );
}
