"use client";

import { isValidElement, useEffect, useMemo, useState } from "react";
import type { ReactNode } from "react";
import { format } from "date-fns";
import { useQuery } from "@tanstack/react-query";
import { Loader2 } from "lucide-react";
import { Badge } from "@/components/ui/badge";
import type { BadgeVariant } from "@/components/ui/badge";
import { Button } from "@/components/ui/button";
import { ScrollArea } from "@/components/ui/scroll-area";
import {
  Sheet,
  SheetContent,
  SheetDescription,
  SheetHeader,
  SheetTitle,
  SheetTrigger,
} from "@/components/ui/sheet";
import { apiGet } from "@/lib/api/client";

const AUDIT_LOG_REFRESH_INTERVAL_MS = 10_000;
const AUDIT_LOG_PAGE_SIZE = 50;
const SUMMARY_MAX_LENGTH = 120;

interface AuditLogDrawerProps {
  sessionId?: string;
  trigger: ReactNode;
}

interface AuditLogEntry {
  id: string;
  userId: string;
  sessionId: string;
  provider: string;
  action: string;
  content: string | null;
  metadata: unknown;
  createdAt: string;
}

interface AuditLogResponse {
  items: AuditLogEntry[];
  total: number;
  page: number;
  pages: number;
}

function isRecord(value: unknown): value is Record<string, unknown> {
  return typeof value === "object" && value !== null;
}

function truncateText(value: string, maxLength: number): string {
  if (value.length <= maxLength) {
    return value;
  }

  return `${value.slice(0, maxLength - 1)}…`;
}

function truncateSessionId(sessionId: string): string {
  return sessionId.slice(0, 8);
}

function formatTimestamp(value: string): string {
  const parsed = new Date(value);

  if (Number.isNaN(parsed.getTime())) {
    return "Unknown";
  }

  return format(parsed, "yyyy-MM-dd HH:mm:ss");
}

function stringifyPayloadValue(value: unknown): string {
  if (typeof value === "string") {
    return value;
  }

  if (typeof value === "number" || typeof value === "boolean") {
    return String(value);
  }

  try {
    return JSON.stringify(value);
  } catch {
    return "[unserializable]";
  }
}

function getPayloadSummary(entry: AuditLogEntry): string {
  const metadata = isRecord(entry.metadata) ? entry.metadata : undefined;
  const payload = metadata && isRecord(metadata.payload) ? metadata.payload : undefined;

  if (typeof entry.content === "string" && entry.content.trim().length > 0) {
    return truncateText(entry.content.trim(), SUMMARY_MAX_LENGTH);
  }

  if (payload) {
    const summary = Object.entries(payload)
      .map(([key, value]) => `${key}=${stringifyPayloadValue(value)}`)
      .join(", ");

    if (summary.length > 0) {
      return truncateText(summary, SUMMARY_MAX_LENGTH);
    }
  }

  return "—";
}

function getActionVariant(action: string): BadgeVariant {
  switch (action) {
    case "inject":
      return "badge-blue";
    case "pause":
      return "status-warning";
    case "resume":
      return "status-success";
    case "kill":
      return "status-error";
    default:
      return "status-neutral";
  }
}

async function fetchAuditLog(
  sessionId: string | undefined,
  page: number
): Promise<AuditLogResponse> {
  const params = new URLSearchParams({
    page: String(page),
    limit: String(AUDIT_LOG_PAGE_SIZE),
  });

  const normalizedSessionId = sessionId?.trim();
  if (normalizedSessionId && normalizedSessionId.length > 0) {
    params.set("sessionId", normalizedSessionId);
  }

  return apiGet<AuditLogResponse>(`/api/mission-control/audit-log?${params.toString()}`);
}

export function AuditLogDrawer({ sessionId, trigger }: AuditLogDrawerProps): React.JSX.Element {
  const [open, setOpen] = useState(false);
  const [page, setPage] = useState(1);

  const triggerElement = useMemo(
    () =>
      isValidElement(trigger) ? (
        trigger
      ) : (
        <Button variant="outline" size="sm">
          {trigger}
        </Button>
      ),
    [trigger]
  );

  const auditLogQuery = useQuery<AuditLogResponse>({
    queryKey: ["mission-control", "audit-log", sessionId ?? "all", page],
    queryFn: async (): Promise<AuditLogResponse> => fetchAuditLog(sessionId, page),
    enabled: open,
    refetchInterval: open ? AUDIT_LOG_REFRESH_INTERVAL_MS : false,
  });

  useEffect(() => {
    if (open) {
      setPage(1);
    }
  }, [open, sessionId]);

  useEffect(() => {
    const pages = auditLogQuery.data?.pages;
    if (pages !== undefined && pages > 0 && page > pages) {
      setPage(pages);
    }
  }, [auditLogQuery.data?.pages, page]);

  const totalItems = auditLogQuery.data?.total ?? 0;
  const totalPages = auditLogQuery.data?.pages ?? 0;
  const items = auditLogQuery.data?.items ?? [];

  const canGoPrevious = page > 1;
  const canGoNext = totalPages > 0 && page < totalPages;
  const errorMessage =
    auditLogQuery.error instanceof Error ? auditLogQuery.error.message : "Failed to load audit log";

  return (
    <Sheet open={open} onOpenChange={setOpen}>
      <SheetTrigger asChild>{triggerElement}</SheetTrigger>
      <SheetContent className="sm:max-w-[920px]">
        <SheetHeader>
          <div className="flex items-center justify-between gap-3">
            <SheetTitle>Audit Log</SheetTitle>
            {auditLogQuery.isFetching ? (
              <Loader2 className="h-4 w-4 animate-spin text-muted-foreground" aria-hidden="true" />
            ) : null}
          </div>
          <SheetDescription>
            {sessionId
              ? `Showing actions for session ${sessionId}.`
              : "Showing operator actions across all mission control sessions."}
          </SheetDescription>
        </SheetHeader>

        <div className="mt-4 flex min-h-0 flex-1 flex-col gap-3">
          <div className="rounded-md border border-border/70">
            <ScrollArea className="h-[64vh]">
              <table className="w-full min-w-[760px] border-collapse text-sm">
                <thead className="sticky top-0 z-10 bg-muted/90">
                  <tr>
                    <th className="px-3 py-2 text-left font-medium text-muted-foreground">
                      Timestamp
                    </th>
                    <th className="px-3 py-2 text-left font-medium text-muted-foreground">
                      Action
                    </th>
                    <th className="px-3 py-2 text-left font-medium text-muted-foreground">
                      Session
                    </th>
                    <th className="px-3 py-2 text-left font-medium text-muted-foreground">
                      Operator
                    </th>
                    <th className="px-3 py-2 text-left font-medium text-muted-foreground">
                      Payload
                    </th>
                  </tr>
                </thead>
                <tbody>
                  {auditLogQuery.isLoading ? (
                    <tr>
                      <td
                        colSpan={5}
                        className="px-3 py-6 text-center text-sm text-muted-foreground"
                      >
                        Loading audit log...
                      </td>
                    </tr>
                  ) : auditLogQuery.error ? (
                    <tr>
                      <td colSpan={5} className="px-3 py-6 text-center text-sm text-red-500">
                        {errorMessage}
                      </td>
                    </tr>
                  ) : items.length === 0 ? (
                    <tr>
                      <td
                        colSpan={5}
                        className="px-3 py-6 text-center text-sm text-muted-foreground"
                      >
                        No audit entries found.
                      </td>
                    </tr>
                  ) : (
                    items.map((entry) => {
                      const payloadSummary = getPayloadSummary(entry);

                      return (
                        <tr key={entry.id} className="border-t border-border/60 align-top">
                          <td className="px-3 py-2 font-mono text-xs text-muted-foreground">
                            {formatTimestamp(entry.createdAt)}
                          </td>
                          <td className="px-3 py-2">
                            <Badge variant={getActionVariant(entry.action)} className="capitalize">
                              {entry.action}
                            </Badge>
                          </td>
                          <td className="px-3 py-2 font-mono text-xs" title={entry.sessionId}>
                            {truncateSessionId(entry.sessionId)}
                          </td>
                          <td
                            className="px-3 py-2 text-xs text-muted-foreground"
                            title={entry.userId}
                          >
                            {entry.userId}
                          </td>
                          <td className="px-3 py-2 text-xs" title={payloadSummary}>
                            {payloadSummary}
                          </td>
                        </tr>
                      );
                    })
                  )}
                </tbody>
              </table>
            </ScrollArea>
          </div>

          <div className="flex items-center justify-between">
            <p className="text-xs text-muted-foreground">{totalItems} total entries</p>
            <div className="flex items-center gap-2">
              <Button
                variant="outline"
                size="sm"
                disabled={!canGoPrevious || auditLogQuery.isFetching}
                onClick={() => {
                  setPage((currentPage) => Math.max(1, currentPage - 1));
                }}
              >
                Previous
              </Button>
              <span className="text-xs text-muted-foreground">
                Page {page} of {Math.max(totalPages, 1)}
              </span>
              <Button
                variant="outline"
                size="sm"
                disabled={!canGoNext || auditLogQuery.isFetching}
                onClick={() => {
                  setPage((currentPage) => currentPage + 1);
                }}
              >
                Next
              </Button>
            </div>
          </div>
        </div>
      </SheetContent>
    </Sheet>
  );
}
