"use client";

import Link from "next/link";
import { useRouter } from "next/navigation";
import { useMemo, useState } from "react";

import { AgentLink } from "@/components/AgentLink";
import { CheckStatusSummary } from "@/components/CheckStatusSummary";
import { ClientPager } from "@/components/ClientPager";
import { EmptyPanel, SummaryCell, Td, Th } from "@/components/DataPanel";
import { DetailTabs } from "@/components/DetailTabs";
import { PageSizeSelect } from "@/components/PageSizeSelect";
import { Pager } from "@/components/Pager";
import { DateTime } from "@/components/TimeZoneControls";
import type { components } from "@/lib/api-types";
import { groupChecks, statusSeverity, type Agent, type CheckGroup } from "@/lib/check-groups";
import { statusBadgeClass } from "@/lib/format";
import {
  DEFAULT_PAGE_SIZE,
  clampPage,
  pageCountOf,
  paginate,
  type PageSize,
} from "@/lib/pagination";
import { usePolling } from "@/lib/usePolling";
import type { InventoryData } from "@/lib/view-types";

type StoredEvent = components["schemas"]["StoredCheckResultEvent"];
type EventsPageData = { items: StoredEvent[]; next_cursor?: string | null; prev_cursor?: string | null };
type TabKey = "agents" | "events";

export function CheckDetailBrowser({
  checkId,
  initialData,
  initialEvents,
  tab,
  eventsLimit,
  eventsCursor,
  eventsBack,
  eventsPage,
}: {
  checkId: string;
  initialData: InventoryData;
  initialEvents: EventsPageData;
  tab: TabKey;
  eventsLimit: PageSize;
  eventsCursor?: string;
  eventsBack: boolean;
  eventsPage: number;
}) {
  const { data } = usePolling(initialData, "/api/poll/inventory");
  const agentsById = useMemo(
    () => new Map(data.agents.map((agent) => [agent.agent_id, agent])),
    [data.agents],
  );
  const group = useMemo(
    () => groupChecks(data.checks, agentsById).find((item) => item.checkId === checkId),
    [agentsById, checkId, data.checks],
  );

  if (!group) {
    return (
      <div>
        <Link href="/checks" className="text-sm text-blue-300 hover:text-blue-200">
          ← checks
        </Link>
        <h1 className="mt-2 text-lg font-semibold">{checkId}</h1>
        <div className="mt-4 text-sm text-neutral-500">Check not found.</div>
      </div>
    );
  }

  return (
    <div className="space-y-6">
      <div>
        <Link href="/checks" className="text-sm text-blue-300 hover:text-blue-200">
          ← checks
        </Link>
        <h1 className="mt-2 text-lg font-semibold">{checkId}</h1>
      </div>
      <dl className="grid grid-cols-[max-content_1fr] gap-x-4 gap-y-1 text-sm">
        <dt className="text-neutral-400">status</dt>
        <dd>
          <CheckStatusSummary counts={group.counts} />
        </dd>
        <dt className="text-neutral-400">agents</dt>
        <dd>{group.checks.length}</dd>
        <dt className="text-neutral-400">last_observed_at</dt>
        <dd>
          <DateTime iso={group.lastObservedAt} />
        </dd>
      </dl>
      <DetailTabs
        current={tab}
        tabs={[
          {
            key: "agents",
            label: "Agents",
            href: `/checks/${encodeURIComponent(checkId)}?tab=agents`,
          },
          {
            key: "events",
            label: "Events",
            href: `/checks/${encodeURIComponent(checkId)}?tab=events&events_limit=${eventsLimit}`,
          },
        ]}
      />
      {tab === "agents" ? (
        <AgentsForCheck group={group} />
      ) : (
        <EventsForCheck
          checkId={checkId}
          initialData={initialEvents}
          agentsById={agentsById}
          eventsLimit={eventsLimit}
          eventsCursor={eventsCursor}
          eventsBack={eventsBack}
          eventsPage={eventsPage}
        />
      )}
    </div>
  );
}

function AgentsForCheck({ group }: { group: CheckGroup }) {
  const rows = useMemo(
    () =>
      [...group.checks].sort(
        (a, b) =>
          statusSeverity[b.check.status] - statusSeverity[a.check.status] ||
          hostName(a).localeCompare(hostName(b)),
      ),
    [group.checks],
  );

  const [pageSize, setPageSize] = useState<PageSize>(DEFAULT_PAGE_SIZE);
  const [page, setPage] = useState(1);
  const onPageSizeChange = (next: PageSize) => {
    setPageSize(next);
    setPage(1);
  };
  const pageCount = pageCountOf(rows.length, pageSize);
  const currentPage = clampPage(page, pageCount);
  const visible = paginate(rows, currentPage, pageSize);

  return (
    <section>
      <div className="mb-3 flex justify-end">
        <PageSizeSelect value={pageSize} onChange={onPageSizeChange} />
      </div>
      <table className="w-full text-sm">
        <thead>
          <tr>
            <Th>HOST</Th>
            <Th>STATUS</Th>
            <Th>LAST_OBSERVED_AT</Th>
            <Th>SUMMARY</Th>
          </tr>
        </thead>
        <tbody>
          {visible.map(({ check, agent }) => (
            <tr key={check.agent_id}>
              <Td>
                <AgentLink agent={agent} agentId={check.agent_id} />
              </Td>
              <Td className={statusBadgeClass(check.status)}>{check.status}</Td>
              <Td>
                <DateTime iso={check.last_observed_at} />
              </Td>
              <SummaryCell text={check.summary} />
            </tr>
          ))}
        </tbody>
      </table>
      <ClientPager page={currentPage} pageCount={pageCount} onPageChange={setPage} />
    </section>
  );
}

function EventsForCheck({
  checkId,
  initialData,
  agentsById,
  eventsLimit,
  eventsCursor,
  eventsBack,
  eventsPage,
}: {
  checkId: string;
  initialData: EventsPageData;
  agentsById: Map<string, Agent>;
  eventsLimit: PageSize;
  eventsCursor?: string;
  eventsBack: boolean;
  eventsPage: number;
}) {
  const router = useRouter();
  const pollUrl = useMemo(() => {
    const qs = new URLSearchParams({
      check_id: checkId,
      limit: String(eventsLimit),
    });
    if (eventsCursor) qs.set("cursor", eventsCursor);
    if (eventsBack) qs.set("back", "1");
    return `/api/poll/events?${qs.toString()}`;
  }, [checkId, eventsCursor, eventsBack, eventsLimit]);
  const { data } = usePolling(initialData, pollUrl);

  const onLimitChange = (next: PageSize) => {
    router.push(
      `/checks/${encodeURIComponent(checkId)}?tab=events&events_limit=${next}`,
    );
  };

  return (
    <section>
      <div className="mb-3 flex justify-end">
        <PageSizeSelect value={eventsLimit} onChange={onLimitChange} />
      </div>
      {data.items.length === 0 ? (
        <EmptyPanel label="No events" />
      ) : (
        <table className="w-full text-sm">
          <thead>
            <tr>
              <Th>OBSERVED_AT</Th>
              <Th>RECEIVED_AT</Th>
              <Th>HOST</Th>
              <Th>STATUS</Th>
              <Th>DURATION_MS</Th>
              <Th>SUMMARY</Th>
            </tr>
          </thead>
          <tbody>
            {data.items.map((event) => {
              const agent = agentsById.get(event.agent_id);
              return (
                <tr key={event.event_id}>
                  <Td>
                    <DateTime iso={event.observed_at} />
                  </Td>
                  <Td>
                    <DateTime iso={event.received_at} />
                  </Td>
                  <Td>
                    <AgentLink agent={agent} agentId={event.agent_id} />
                  </Td>
                  <Td className={statusBadgeClass(event.status)}>{event.status}</Td>
                  <Td>{event.duration_ms}</Td>
                  <SummaryCell text={event.output} />
                </tr>
              );
            })}
          </tbody>
        </table>
      )}
      <Pager
        basePath={`/checks/${encodeURIComponent(checkId)}`}
        prevCursor={data.prev_cursor}
        nextCursor={data.next_cursor}
        page={eventsPage}
        extra={{ tab: "events", events_limit: String(eventsLimit) }}
      />
    </section>
  );
}

function hostName(row: { agent?: Agent; check: { agent_id: string } }): string {
  return row.agent?.hostname || row.check.agent_id;
}
