import { useMemo, useState } from "react";
import { ApiError } from "../../api/client";
import type { SupportCode } from "../../api/types";
import { useAuth } from "../../auth/AuthContext";
import { PageHeader } from "../../components/layout/PageHeader";
import { PlusIcon, RefreshIcon, SearchIcon, TrashIcon } from "../../components/layout/icons";
import { Badge } from "../../components/ui/Badge";
import { Button } from "../../components/ui/Button";
import { Input } from "../../components/ui/Input";
import { Panel } from "../../components/ui/Panel";
import { EmptyState, ErrorState } from "../../components/ui/States";
import { codeLabel, codeTone } from "../../components/ui/status";
import { Table, type Column } from "../../components/ui/Table";
import { TableSkeleton } from "../../components/ui/TableSkeleton";
import { absoluteTime, relativeTime } from "../../lib/time";
import { CancelCodeDialog } from "./CancelCodeDialog";
import { GenerateCodeModal } from "./GenerateCodeModal";
import { useSupportCodes } from "./hooks";
import "./codes.css";

/** A code is still cancellable only while it is pending or connected. */
function canCancel(status: string): boolean {
  return status === "pending" || status === "connected";
}

export function SupportCodesPage() {
  const { user } = useAuth();
  const codesQuery = useSupportCodes();
  const [filter, setFilter] = useState("");
  const [generating, setGenerating] = useState(false);
  const [cancelFor, setCancelFor] = useState<SupportCode | null>(null);

  const { data } = codesQuery;
  const codes = useMemo(() => data ?? [], [data]);

  // Newest first: the in-memory map the server returns has no guaranteed order,
  // and the code a tech just generated should be at the top where they expect
  // it.
  const sorted = useMemo(
    () =>
      [...codes].sort(
        (a, b) =>
          new Date(b.created_at).getTime() - new Date(a.created_at).getTime(),
      ),
    [codes],
  );

  const filtered = useMemo(() => {
    const q = filter.trim().toLowerCase();
    if (!q) return sorted;
    return sorted.filter(
      (c) =>
        c.code.toLowerCase().includes(q) ||
        c.created_by.toLowerCase().includes(q) ||
        (c.client_machine?.toLowerCase().includes(q) ?? false),
    );
  }, [sorted, filter]);

  const pendingCount = useMemo(
    () => codes.filter((c) => c.status === "pending").length,
    [codes],
  );

  const columns: Column<SupportCode>[] = [
    {
      key: "code",
      header: "Code",
      render: (c) => <span className="cdt__code">{c.code}</span>,
    },
    {
      key: "status",
      header: "Status",
      render: (c) => (
        <Badge tone={codeTone(c.status)} dot>
          {codeLabel(c.status)}
        </Badge>
      ),
    },
    {
      key: "bound",
      header: "Bound to",
      render: (c) =>
        c.client_machine || c.client_name ? (
          <div className="cdt__bound">
            <span className="dt__strong">
              {c.client_machine ?? c.client_name}
            </span>
            {c.client_machine && c.client_name && (
              <span className="cdt__boundsub">{c.client_name}</span>
            )}
          </div>
        ) : (
          <span className="dt__muted">Not redeemed</span>
        ),
    },
    {
      key: "created_by",
      header: "Created by",
      render: (c) => <span className="dt__strong">{c.created_by}</span>,
    },
    {
      key: "created",
      header: "Created",
      render: (c) => (
        <span className="dt__mono" title={absoluteTime(c.created_at)}>
          {relativeTime(c.created_at)}
        </span>
      ),
    },
    {
      key: "actions",
      header: "",
      cellClass: "dt__actions",
      render: (c) => {
        const cancellable = canCancel(c.status);
        return (
          <span className="dt__rowactions" onClick={(e) => e.stopPropagation()}>
            <Button
              variant="danger"
              size="sm"
              onClick={() => setCancelFor(c)}
              disabled={!cancellable}
              title={
                cancellable
                  ? undefined
                  : `${codeLabel(c.status)} codes cannot be cancelled`
              }
              aria-label={`Cancel code ${c.code}`}
            >
              <TrashIcon width={14} height={14} />
              Cancel
            </Button>
          </span>
        );
      },
    },
  ];

  return (
    <div className="page">
      <PageHeader
        title="Support codes"
        subtitle="One-time codes for attended support. Generate a code, read it to the end user, and they redeem it to start a session."
        actions={
          <>
            <Button
              variant="ghost"
              onClick={() => void codesQuery.refetch()}
              loading={codesQuery.isFetching}
            >
              <RefreshIcon width={15} height={15} />
              Refresh
            </Button>
            <Button variant="primary" onClick={() => setGenerating(true)}>
              <PlusIcon width={15} height={15} />
              Generate code
            </Button>
          </>
        }
      />

      <Panel flush>
        <div style={{ padding: "14px 16px 0" }}>
          <div className="toolbar">
            <div className="searchbox">
              <span className="searchbox__icon">
                <SearchIcon width={15} height={15} />
              </span>
              <Input
                placeholder="Filter by code, machine, or creator"
                value={filter}
                onChange={(e) => setFilter(e.target.value)}
                aria-label="Filter support codes"
              />
            </div>
            <div className="toolbar__count">
              <span className="mono">{pendingCount}</span> awaiting redeem ·{" "}
              <span className="mono">{codes.length}</span> active
            </div>
          </div>
        </div>

        {codesQuery.isLoading ? (
          <>
            <span className="visually-hidden" role="status">
              Loading support codes
            </span>
            <TableSkeleton
              headers={[
                "Code",
                "Status",
                "Bound to",
                "Created by",
                "Created",
                "",
              ]}
            />
          </>
        ) : codesQuery.isError ? (
          <ErrorState
            title="Could not load support codes"
            message={
              codesQuery.error instanceof ApiError
                ? codesQuery.error.message
                : "The GuruConnect relay did not respond. Check the relay status, then retry."
            }
            action={
              <Button variant="primary" onClick={() => void codesQuery.refetch()}>
                Retry
              </Button>
            }
          />
        ) : filtered.length === 0 ? (
          filter ? (
            <EmptyState
              title="No matching codes"
              message={`Nothing matches "${filter}". Clear the filter to see every active code.`}
              action={
                <Button variant="ghost" onClick={() => setFilter("")}>
                  Clear filter
                </Button>
              }
            />
          ) : (
            <EmptyState
              title="No active codes"
              message="Generate a code, read it to the end user over the phone, and they redeem it to start an attended session. Each code works once."
              action={
                <Button variant="primary" onClick={() => setGenerating(true)}>
                  <PlusIcon width={15} height={15} />
                  Generate code
                </Button>
              }
            />
          )
        ) : (
          <Table columns={columns} rows={filtered} rowKey={(c) => c.code} />
        )}
      </Panel>

      <GenerateCodeModal
        open={generating}
        technicianName={user?.username}
        onClose={() => setGenerating(false)}
      />
      <CancelCodeDialog code={cancelFor} onClose={() => setCancelFor(null)} />
    </div>
  );
}
