"use client";

import { useMemo } from "react";
import Link from "next/link";
import { useQuery } from "@tanstack/react-query";
import { ArrowUpRight, Store, 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 { 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 { useI18n, useT } from "@/i18n";
import { friendlyErrorMessage } from "@/lib/errors";
import { formatCurrency, formatDateTime, formatNumber } from "@/lib/format";
import { queryKeys } from "@/lib/query-keys";
import { useUrlState } from "@/lib/use-url-state";
import { getStoreBalances, keyedTotals, STORE_BALANCE_STATES } from "@/services/store-ledger";
import type { StoreBalanceState } from "@/types/store-ledger";

/**
 * Store accounts: which shops owe us, and which we owe.
 *
 * **The question this answers had no answer before it.** The statement screens are period reports
 * and cannot accumulate; the settlements table records payouts and was never subtracted from them.
 * So a shop whose customers pay it directly — we collect nothing and charge a fee on every
 * delivery — ran up a debt that scrolled out of view every time the month rolled over.
 *
 * **Largest balance first, whichever direction it points.** The server orders it that way because
 * the first question is where the most money is sitting, not who owes it; a shop owing 400,000
 * matters more than one we owe 80. `state=owes` narrows it to the chase list.
 *
 * The headline figures describe **every** store, not the page on screen — they travel beside the
 * page precisely so paging through cannot make the totals look smaller.
 */
export default function StoreAccountsPage() {
  const t = useT();
  const { locale } = useI18n();

  const [page, setPage] = useUrlState("page", 1, (value) => {
    const parsed = Number(value);
    return Number.isFinite(parsed) && parsed > 0 ? parsed : 1;
  });
  const [state, setState] = useUrlState<StoreBalanceState | "">("state", "", (value) =>
    STORE_BALANCE_STATES.includes(value as StoreBalanceState) ? (value as StoreBalanceState) : "",
  );

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

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

  const rows = data?.Model ?? [];
  const totals = keyedTotals(data?.Totals);

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

      {/*
        Said before the figures, not after them: "owed" and "owes" are read from our side of the
        table, and somebody who assumes the opposite chases the wrong shop for money.
      */}
      <div className="mb-4 flex items-start gap-2 rounded-lg border bg-muted/40 p-3 text-xs text-muted-foreground">
        <Wallet className="mt-0.5 h-4 w-4 shrink-0 text-primary" aria-hidden />
        <span>{t("storeAccounts.whoseMoney")}</span>
      </div>

      {Object.entries(totals).length > 0 ? (
        <div className="mb-4 grid gap-3 sm:grid-cols-2">
          {Object.entries(totals).map(([currency, figures]) => (
            <Card key={currency} className="p-4">
              <p className="text-xs font-medium uppercase tracking-wide text-muted-foreground">
                {currency}
              </p>
              <div className="mt-2 grid grid-cols-2 gap-3">
                <div>
                  <p className="text-xs text-muted-foreground">
                    {t("storeAccounts.totalsOwedByStores")}
                  </p>
                  <p className="numeric text-lg font-semibold text-warning">
                    {formatCurrency(figures.owed_by_stores, currency, locale)}
                  </p>
                  <p className="text-[11px] text-muted-foreground">
                    {t("storeAccounts.storesOwed", { count: figures.stores_owing })}
                  </p>
                </div>
                <div>
                  <p className="text-xs text-muted-foreground">
                    {t("storeAccounts.totalsOwedToStores")}
                  </p>
                  <p className="numeric text-lg font-semibold">
                    {formatCurrency(figures.owed_to_stores, currency, locale)}
                  </p>
                  <p className="text-[11px] text-muted-foreground">
                    {t("storeAccounts.storesOwed", { count: figures.stores_owed })}
                  </p>
                </div>
              </div>
            </Card>
          ))}
        </div>
      ) : null}

      <Card>
        <div className="flex flex-wrap items-center justify-end gap-3 border-b p-4">
          <div className="flex items-center gap-2">
            <span className="text-xs text-muted-foreground">{t("storeAccounts.filterState")}</span>
            <Select
              value={state || "all"}
              onValueChange={(value) => {
                setPage(1);
                setState(value === "all" ? "" : (value as StoreBalanceState));
              }}
            >
              <SelectTrigger className="w-[11rem]">
                <SelectValue />
              </SelectTrigger>
              <SelectContent>
                <SelectItem value="all">{t("storeAccounts.allStates")}</SelectItem>
                {STORE_BALANCE_STATES.map((option) => (
                  <SelectItem key={option} value={option}>
                    {t(`ledger.state.${option}`)}
                  </SelectItem>
                ))}
              </SelectContent>
            </Select>
          </div>
        </div>

        {isLoading ? (
          <TableSkeleton rows={6} cols={7} />
        ) : isError ? (
          <ErrorState message={friendlyErrorMessage(error, t)} onRetry={() => refetch()} />
        ) : rows.length === 0 ? (
          <EmptyState
            title={t("storeAccounts.empty")}
            description={t("storeAccounts.emptyHint")}
            icon={Store}
          />
        ) : (
          <div className="overflow-x-auto">
            <Table>
              <TableHeader>
                <TableRow>
                  <TableHead>{t("storeAccounts.store")}</TableHead>
                  <TableHead>{t("storeAccounts.currency")}</TableHead>
                  <TableHead className="text-end">{t("storeAccounts.owedByStore")}</TableHead>
                  <TableHead className="text-end">{t("storeAccounts.owedToStore")}</TableHead>
                  <TableHead>{t("storeAccounts.balance")}</TableHead>
                  <TableHead className="text-end">{t("storeAccounts.entries")}</TableHead>
                  <TableHead>{t("storeAccounts.lastMovement")}</TableHead>
                  <TableHead aria-label={t("common.actions")} />
                </TableRow>
              </TableHeader>
              <TableBody>
                {rows.map((row) => (
                  <TableRow key={`${row.store.uuid}-${row.currency}`}>
                    <TableCell className="font-medium">{row.store.name}</TableCell>

                    {/*
                      The currency gets a column of its own so the two money columns do not have to
                      carry it. Repeating "ل.س" in every cell made each figure a long mixed string
                      whose edges drifted away from the column it belonged to — the clearest way to
                      lose track of which heading a number answers to.
                    */}
                    <TableCell className="text-xs font-medium text-muted-foreground">
                      {row.currency}
                    </TableCell>

                    {/*
                      Both directions get their own column rather than one signed figure. An
                      accountant reading down a list should not have to notice a minus sign to see
                      which way a number points.
                    */}
                    <TableCell className="numeric whitespace-nowrap text-end font-medium text-warning">
                      {row.owed_by_store > 0 ? formatNumber(row.owed_by_store, locale) : "—"}
                    </TableCell>
                    <TableCell className="numeric whitespace-nowrap text-end font-medium">
                      {row.owed_to_store > 0 ? formatNumber(row.owed_to_store, locale) : "—"}
                    </TableCell>

                    <TableCell>
                      <BalanceStateBadge state={row.state} label={row.state_label} />
                    </TableCell>
                    <TableCell className="numeric text-end text-muted-foreground">
                      {row.entries_count}
                    </TableCell>
                    <TableCell className="whitespace-nowrap text-xs text-muted-foreground">
                      {formatDateTime(row.last_movement_at, locale)}
                    </TableCell>
                    <TableCell>
                      <div className="flex items-center justify-end">
                        <Link
                          href={`/payments/stores/${row.store.uuid}`}
                          className="inline-flex items-center gap-1 text-xs font-medium text-primary hover:underline"
                        >
                          {t("storeAccounts.openAccount")}
                          <ArrowUpRight className="h-3 w-3 rtl:-scale-x-100" aria-hidden />
                        </Link>
                      </div>
                    </TableCell>
                  </TableRow>
                ))}
              </TableBody>
            </Table>
          </div>
        )}

        {data ? (
          <Pagination
            page={data.Page}
            totalPages={data.Total}
            records={data.Records}
            onPageChange={(next) => setPage(next)}
          />
        ) : null}
      </Card>
    </div>
  );
}
