"use client";

import { useMemo, useState } from "react";
import Link from "next/link";
import { useQuery } from "@tanstack/react-query";
import { ArrowUpRight, HandCoins, Wallet } from "lucide-react";
import { PageHeader } from "@/components/shared/page-header";
import { Pagination } from "@/components/shared/pagination";
import { EmptyState, ErrorState, TableSkeleton } from "@/components/shared/states";
import { BalanceStateBadge } from "@/components/shared/ledger-badges";
import { Button } from "@/components/ui/button";
import { Card } from "@/components/ui/card";
import {
  Select,
  SelectContent,
  SelectItem,
  SelectTrigger,
  SelectValue,
} from "@/components/ui/select";
import {
  Table,
  TableBody,
  TableCell,
  TableHead,
  TableHeader,
  TableRow,
} from "@/components/ui/table";
import { Tabs, TabsContent, TabsList, TabsTrigger } from "@/components/ui/tabs";
import { LedgerFeed } from "@/features/ledger/ledger-feed";
import { SettleDialog } from "@/features/ledger/settle-dialog";
import { useCan } from "@/features/auth/use-can";
import { useI18n, useT } from "@/i18n";
import { formatCurrency, formatDateTime, formatPhone } from "@/lib/format";
import { friendlyErrorMessage } from "@/lib/errors";
import { queryKeys } from "@/lib/query-keys";
import { useUrlState } from "@/lib/use-url-state";
import { BALANCE_STATES, getCaptainBalances, keyedMap } from "@/services/ledger";
import type { CaptainBalance, CaptainBalanceState, CurrencyTotals } from "@/types/ledger";

/** Which half of the desk is on screen: where the money sits, or what moved. */
type DeskTab = "balances" | "movements";

/**
 * The cash desk: every captain with money outstanding, and clearing it.
 *
 * Captains carry money both ways. They pay suppliers out of their own pockets, which the company
 * then owes them; and they take cash from customers, which they then owe the company. This screen
 * is where the two meet the cashier.
 *
 * **Largest balance first**, not alphabetical: the server orders it that way, because the captain
 * owing the most is the one worth chasing before the end of the shift, and a cashier should not
 * have to sort a list to find them.
 *
 * The headline figures describe **every** captain, not the page on screen — they travel beside
 * the page precisely so that paging through the list cannot make the totals look smaller.
 */
export default function PaymentsPage() {
  const t = useT();
  const { locale } = useI18n();
  const { can } = useCan();
  const canSettle = can("captain_ledger.settle");

  const [page, setPage] = useUrlState("page", 1, (value) => {
    const parsed = Number(value);
    return Number.isFinite(parsed) && parsed > 0 ? parsed : 1;
  });
  const [state, setState] = useUrlState<CaptainBalanceState | "">("state", "", (value) =>
    BALANCE_STATES.includes(value as CaptainBalanceState) ? (value as CaptainBalanceState) : "",
  );
  const [currency, setCurrency] = useUrlState("currency", "", (value) => value.toUpperCase());
  const [tab, setTab] = useUrlState<DeskTab>("tab", "balances", (value) =>
    value === "movements" ? "movements" : "balances",
  );

  const filters = useMemo(
    () => ({ page, rows: 15, state: state || undefined, currency: currency || undefined }),
    [page, state, currency],
  );

  const { data, isLoading, isError, error, refetch } = useQuery({
    queryKey: queryKeys.ledger.balances(filters),
    queryFn: () => getCaptainBalances(filters),
  });

  const balances = data?.Model ?? [];
  const totals = keyedMap(data?.Totals);
  const currencies = Object.keys(totals).sort();

  // The row whose settle dialog is open. Held as the row itself so the dialog settles against
  // the figures the cashier was looking at when they clicked.
  const [settling, setSettling] = useState<CaptainBalance | null>(null);

  return (
    <div>
      <PageHeader title={t("payments.title")} subtitle={t("payments.subtitle")} />

      <Tabs value={tab} onValueChange={(value) => setTab(value as DeskTab)}>
        <TabsList className="mb-4">
          <TabsTrigger value="balances">{t("ledger.tab.balances")}</TabsTrigger>
          <TabsTrigger value="movements">{t("ledger.tab.movements")}</TabsTrigger>
        </TabsList>

        <TabsContent value="movements">
          <LedgerFeed />
        </TabsContent>

        <TabsContent value="balances">
      {isLoading ? null : currencies.length === 0 ? null : (
        <div className="mb-4 space-y-3">
          {currencies.map((code) => (
            <TotalsRow key={code} currency={code} totals={totals[code]} locale={locale} />
          ))}
        </div>
      )}

      <Card>
        <div className="flex flex-wrap items-center justify-between gap-3 border-b p-4">
          <p className="text-sm text-muted-foreground">{t("ledger.listHint")}</p>
          <div className="flex flex-wrap items-center gap-2">
            <Select
              value={state || "all"}
              onValueChange={(value) => {
                setState(value === "all" ? "" : (value as CaptainBalanceState));
                setPage(1);
              }}
            >
              <SelectTrigger className="w-[11rem]">
                <SelectValue />
              </SelectTrigger>
              <SelectContent>
                <SelectItem value="all">{t("ledger.filter.allCaptains")}</SelectItem>
                {BALANCE_STATES.map((option) => (
                  <SelectItem key={option} value={option}>
                    {t(`ledger.state.${option}`)}
                  </SelectItem>
                ))}
              </SelectContent>
            </Select>

            {/* Only offered once there is more than one currency to choose between. */}
            {currencies.length > 1 ? (
              <Select
                value={currency || "all"}
                onValueChange={(value) => {
                  setCurrency(value === "all" ? "" : value);
                  setPage(1);
                }}
              >
                <SelectTrigger className="w-[8rem]">
                  <SelectValue />
                </SelectTrigger>
                <SelectContent>
                  <SelectItem value="all">{t("ledger.filter.allCurrencies")}</SelectItem>
                  {currencies.map((code) => (
                    <SelectItem key={code} value={code}>
                      {code}
                    </SelectItem>
                  ))}
                </SelectContent>
              </Select>
            ) : null}
          </div>
        </div>

        {isLoading ? (
          <TableSkeleton rows={8} cols={6} />
        ) : isError ? (
          <ErrorState message={friendlyErrorMessage(error, t)} onRetry={() => refetch()} />
        ) : balances.length === 0 ? (
          <EmptyState
            title={state || currency ? t("ledger.emptyFiltered") : t("ledger.empty")}
            description={t("ledger.emptyHint")}
            icon={Wallet}
          />
        ) : (
          <>
            <div className="overflow-x-auto">
              <Table>
                <TableHeader>
                  <TableRow>
                    <TableHead>{t("ledger.captain")}</TableHead>
                    <TableHead>{t("ledger.position")}</TableHead>
                    <TableHead className="text-end">{t("ledger.outstanding")}</TableHead>
                    <TableHead>{t("ledger.entries")}</TableHead>
                    <TableHead>{t("ledger.lastMovement")}</TableHead>
                    <TableHead aria-label={t("common.actions")} />
                  </TableRow>
                </TableHeader>
                <TableBody>
                  {balances.map((row) => (
                    <BalanceRow
                      key={`${row.captain?.uuid ?? "unknown"}-${row.currency}`}
                      row={row}
                      locale={locale}
                      canSettle={canSettle}
                      onSettle={() => setSettling(row)}
                    />
                  ))}
                </TableBody>
              </Table>
            </div>
            <Pagination
              page={data!.Page}
              totalPages={data!.Total}
              records={data!.Records}
              onPageChange={(next) => setPage(next)}
            />
          </>
        )}
      </Card>

        </TabsContent>
      </Tabs>

      {settling && settling.captain && settling.settle_with ? (
        <SettleDialog
          open
          onOpenChange={(open) => {
            if (!open) setSettling(null);
          }}
          captainUlid={settling.captain.uuid}
          captainName={settling.captain.name}
          currency={settling.currency}
          outstanding={settling.outstanding}
          direction={settling.settle_with.direction}
        />
      ) : null}
    </div>
  );
}

/**
 * One currency's position across the whole fleet.
 *
 * Two directions, never netted into one figure. "We owe captains 800 and they owe us 1,200" is two
 * jobs for the cashier — find 800, collect 1,200 — and a single "net 400 owed to us" would hide
 * both of them behind a number nobody can act on.
 */
function TotalsRow({
  currency,
  totals,
  locale,
}: {
  currency: string;
  totals: CurrencyTotals;
  locale: "en" | "ar";
}) {
  const t = useT();

  return (
    <div className="grid grid-cols-1 gap-3 sm:grid-cols-2">
      <Card className="p-4">
        <div className="flex items-start justify-between gap-2">
          <div>
            <p className="text-xs text-muted-foreground">{t("ledger.totals.owedByCaptains")}</p>
            <p className="mt-1 text-2xl font-semibold text-warning">
              {formatCurrency(totals.owed_by_captains, currency, locale)}
            </p>
            <p className="mt-0.5 text-xs text-muted-foreground">
              {t("ledger.totals.captainsOwing", { count: totals.captains_owing })}
            </p>
          </div>
          <HandCoins className="h-5 w-5 text-warning" aria-hidden />
        </div>
      </Card>
      <Card className="p-4">
        <div className="flex items-start justify-between gap-2">
          <div>
            <p className="text-xs text-muted-foreground">{t("ledger.totals.owedToCaptains")}</p>
            <p className="mt-1 text-2xl font-semibold text-primary">
              {formatCurrency(totals.owed_to_captains, currency, locale)}
            </p>
            <p className="mt-0.5 text-xs text-muted-foreground">
              {t("ledger.totals.captainsOwed", { count: totals.captains_owed })}
            </p>
          </div>
          <Wallet className="h-5 w-5 text-primary" aria-hidden />
        </div>
      </Card>
    </div>
  );
}

function BalanceRow({
  row,
  locale,
  canSettle,
  onSettle,
}: {
  row: CaptainBalance;
  locale: "en" | "ar";
  canSettle: boolean;
  onSettle: () => void;
}) {
  const t = useT();

  return (
    <TableRow>
      <TableCell>
        {row.captain ? (
          <>
            <Link
              href={`/payments/captains/${row.captain.uuid}`}
              className="font-medium text-foreground hover:underline"
            >
              {row.captain.name}
            </Link>
            {row.captain.phone ? (
              <p className="text-xs text-muted-foreground" dir="ltr">
                {formatPhone(row.captain.phone)}
              </p>
            ) : null}
          </>
        ) : (
          <span className="italic text-muted-foreground">{t("ledger.unknownCaptain")}</span>
        )}
      </TableCell>

      <TableCell>
        {/*
          Our own wording rather than the server's `state_label`, so this list, the statement page
          and the filter above all name a state the same way — the statement endpoint returns
          bare balances and has no label to borrow.
        */}
        <BalanceStateBadge state={row.state} label={t(`ledger.state.${row.state}`)} />
      </TableCell>

      {/*
        The unsigned amount, with the badge beside it saying which way it points. A bare signed
        number makes the reader do the sign convention in their head, and "-120" reads as "a
        loss" to most people rather than as "the captain owes us 120".
      */}
      <TableCell className="numeric text-end font-medium">
        {row.state === "clear" ? (
          <span className="text-muted-foreground">—</span>
        ) : (
          formatCurrency(row.outstanding, row.currency, locale)
        )}
      </TableCell>

      <TableCell className="numeric text-muted-foreground">{row.entries_count}</TableCell>

      <TableCell className="text-xs text-muted-foreground">
        {row.last_movement_at ? formatDateTime(row.last_movement_at, locale) : "—"}
      </TableCell>

      <TableCell>
        <div className="flex items-center justify-end gap-2">
          {canSettle && row.settle_with && row.captain ? (
            <Button size="sm" variant="outline" onClick={onSettle}>
              {row.settle_with.direction === "cash_paid_out"
                ? t("ledger.settle.payoutConfirm")
                : t("ledger.settle.handInConfirm")}
            </Button>
          ) : null}
          {row.captain ? (
            <Link
              href={`/payments/captains/${row.captain.uuid}`}
              className="inline-flex items-center gap-1 text-xs font-medium text-primary hover:underline"
            >
              {t("ledger.statement")}
              <ArrowUpRight className="h-3 w-3" aria-hidden />
            </Link>
          ) : null}
        </div>
      </TableCell>
    </TableRow>
  );
}
