"use client";

import { useMemo, useState } from "react";
import Link from "next/link";
import { useParams } from "next/navigation";
import { useQuery } from "@tanstack/react-query";
import { ArrowLeft, ReceiptText, SlidersHorizontal } 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 { StatusBadge } from "@/components/ui/badge";
import { Button } from "@/components/ui/button";
import { Card } from "@/components/ui/card";
import {
  Table,
  TableBody,
  TableCell,
  TableHead,
  TableHeader,
  TableRow,
} from "@/components/ui/table";
import { useCan } from "@/features/auth/use-can";
import { StoreSettleDialog } from "@/features/store-ledger/store-settle-dialog";
import { useI18n, useT } from "@/i18n";
import { friendlyErrorMessage } from "@/lib/errors";
import { formatCurrency, formatDateTime } from "@/lib/format";
import { queryKeys } from "@/lib/query-keys";
import { useUrlState } from "@/lib/use-url-state";
import { getStoreClient } from "@/services/store-clients";
import { getStoreAccount, getStoreStatement } from "@/services/store-ledger";
import type { StoreAccountBalance, StoreLedgerEntryType } from "@/types/store-ledger";

/**
 * The breakdown arrives keyed by entry type, which `Object.entries` widens to `string`. Narrowed
 * here rather than cast at the call site, so an unknown key shows itself rather than rendering as
 * a raw `storeAccounts.type.whatever`.
 */
const BREAKDOWN_TYPES: StoreLedgerEntryType[] = [
  "cod_collected",
  "delivery_fee",
  "paid_to_store",
  "received_from_store",
  "adjustment",
];

function typeLabel(t: (key: never) => string, type: string): string {
  return BREAKDOWN_TYPES.includes(type as StoreLedgerEntryType)
    ? t(`storeAccounts.type.${type as StoreLedgerEntryType}` as never)
    : type;
}

/**
 * One store's account: what it comes to, what made it, and every movement behind it.
 *
 * **The balance is split into what we owe and what they owe, in words.** A single signed figure is
 * how somebody ends up chasing a shop we are holding money for.
 *
 * The statement is the audit trail, and every row that came from an order says which order — a fee
 * charged for a delivery that never arrived carries the captain's reason on it, because that is the
 * line a shop queries and a statement that cannot answer it generates an email instead.
 */
export default function StoreAccountPage() {
  const t = useT();
  const { locale } = useI18n();
  const { can } = useCan();
  const canSettle = can("store_ledger.settle");

  const params = useParams<{ uuid: string }>();
  const storeUuid = params.uuid;

  const [page, setPage] = useUrlState("page", 1, (value) => {
    const parsed = Number(value);
    return Number.isFinite(parsed) && parsed > 0 ? parsed : 1;
  });

  const [dialog, setDialog] = useState<{ mode: "settle" | "adjust"; balance: StoreAccountBalance } | null>(
    null,
  );

  const account = useQuery({
    queryKey: queryKeys.storeLedger.account(storeUuid),
    queryFn: () => getStoreAccount(storeUuid),
  });

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

  const statement = useQuery({
    queryKey: queryKeys.storeLedger.statement(storeUuid, filters),
    queryFn: () => getStoreStatement(storeUuid, filters),
  });

  const balances = account.data?.Model?.balances ?? [];
  const entries = statement.data?.Model ?? [];

  /*
   * The account payload carries balances, not a name — the shop is identified by the uuid in the
   * path. Read separately so the heading and the dialogs can say which shop this is; a screen about
   * somebody's money should never be headed by a uuid.
   */
  const store = useQuery({
    queryKey: queryKeys.storeClients.detail(storeUuid),
    queryFn: () => getStoreClient(storeUuid),
  });

  const storeName = store.data?.Model?.name ?? "";

  return (
    <div>
      <Link
        href="/payments/stores"
        className="mb-3 inline-flex items-center gap-1 text-xs font-medium text-muted-foreground hover:text-foreground"
      >
        <ArrowLeft className="h-3 w-3 rtl:rotate-180" aria-hidden />
        {t("storeAccounts.backToList")}
      </Link>

      <PageHeader
        title={storeName || t("storeAccounts.account")}
        subtitle={t("storeAccounts.accountSubtitle")}
      />

      {account.isLoading ? (
        <TableSkeleton rows={2} cols={3} />
      ) : account.isError ? (
        <ErrorState
          message={friendlyErrorMessage(account.error, t)}
          onRetry={() => account.refetch()}
        />
      ) : balances.length === 0 ? (
        <EmptyState
          title={t("storeAccounts.noEntries")}
          description={t("storeAccounts.emptyHint")}
          icon={ReceiptText}
        />
      ) : (
        <div className="mb-4 grid gap-3 sm:grid-cols-2">
          {balances.map((balance) => (
            <Card key={balance.currency} className="p-4">
              <div className="flex items-start justify-between gap-3">
                <div>
                  <p className="text-xs font-medium uppercase tracking-wide text-muted-foreground">
                    {balance.currency}
                  </p>
                  <p className="numeric mt-1 text-2xl font-semibold">
                    {formatCurrency(
                      balance.owed_by_store > 0 ? balance.owed_by_store : balance.owed_to_store,
                      balance.currency,
                      locale,
                    )}
                  </p>
                  <div className="mt-1">
                    <BalanceStateBadge state={balance.state} label={balance.state_label} />
                  </div>
                </div>

                {canSettle ? (
                  <div className="flex flex-col gap-2">
                    <Button size="sm" onClick={() => setDialog({ mode: "settle", balance })}>
                      {t("storeAccounts.settle")}
                    </Button>
                    <Button
                      size="sm"
                      variant="outline"
                      onClick={() => setDialog({ mode: "adjust", balance })}
                    >
                      <SlidersHorizontal className="me-1.5 h-3.5 w-3.5" aria-hidden />
                      {t("storeAccounts.adjust")}
                    </Button>
                  </div>
                ) : null}
              </div>

              {Object.keys(balance.breakdown).length > 0 ? (
                <div className="mt-3 border-t pt-3">
                  <p className="mb-1 text-xs text-muted-foreground">
                    {t("storeAccounts.breakdown")}
                  </p>
                  <ul className="space-y-1">
                    {Object.entries(balance.breakdown).map(([type, total]) => (
                      <li key={type} className="flex items-center justify-between text-xs">
                        <span className="text-muted-foreground">{typeLabel(t, type)}</span>
                        <span className="numeric font-medium">
                          {formatCurrency(total, balance.currency, locale)}
                        </span>
                      </li>
                    ))}
                  </ul>
                </div>
              ) : null}
            </Card>
          ))}
        </div>
      )}

      <Card>
        <div className="border-b p-4">
          <p className="text-sm font-medium">{t("storeAccounts.statement")}</p>
        </div>

        {statement.isLoading ? (
          <TableSkeleton rows={6} cols={5} />
        ) : statement.isError ? (
          <ErrorState
            message={friendlyErrorMessage(statement.error, t)}
            onRetry={() => statement.refetch()}
          />
        ) : entries.length === 0 ? (
          <EmptyState title={t("storeAccounts.noEntries")} icon={ReceiptText} />
        ) : (
          <>
            <div className="overflow-x-auto">
              <Table>
                <TableHeader>
                  <TableRow>
                    <TableHead>{t("storeAccounts.entryType")}</TableHead>
                    <TableHead>{t("storeAccounts.order")}</TableHead>
                    <TableHead className="text-end">{t("storeAccounts.amount")}</TableHead>
                    <TableHead className="text-end">{t("storeAccounts.balanceAfter")}</TableHead>
                    <TableHead>{t("ledger.when")}</TableHead>
                  </TableRow>
                </TableHeader>
                <TableBody>
                  {entries.map((entry) => (
                    <TableRow key={entry.uuid}>
                      <TableCell>
                        <p className="text-sm font-medium">{entry.type_label}</p>
                        {/*
                          The reason a charge exists, on the row that charges it. A fee against an
                          order that never arrived is the line a shop asks about.
                        */}
                        {entry.note ? (
                          <p className="text-xs text-muted-foreground">{entry.note}</p>
                        ) : null}
                        {entry.reference ? (
                          <p className="text-[11px] text-muted-foreground" dir="ltr">
                            {entry.reference}
                          </p>
                        ) : null}
                      </TableCell>

                      <TableCell>
                        {entry.order ? (
                          <Link
                            href={`/orders/${entry.order.uuid}`}
                            className="text-xs font-medium text-primary hover:underline"
                          >
                            {entry.order.order_number}
                          </Link>
                        ) : (
                          <span className="text-xs text-muted-foreground">—</span>
                        )}
                        {entry.order?.status === "delivery_failed" ? (
                          <div className="mt-1">
                            <StatusBadge variant="warning">{entry.order.status_label}</StatusBadge>
                          </div>
                        ) : null}
                      </TableCell>

                      <TableCell
                        className={
                          entry.direction === "credit"
                            ? "numeric text-end font-medium text-primary"
                            : "numeric text-end font-medium text-warning"
                        }
                      >
                        {entry.direction === "credit" ? "+" : "−"}
                        {formatCurrency(Math.abs(entry.amount), entry.currency, locale)}
                      </TableCell>

                      <TableCell className="numeric whitespace-nowrap text-end text-muted-foreground">
                        {formatCurrency(entry.balance_after, entry.currency, locale)}
                      </TableCell>

                      <TableCell className="whitespace-nowrap text-xs text-muted-foreground">
                        {formatDateTime(entry.created_at, locale)}
                      </TableCell>
                    </TableRow>
                  ))}
                </TableBody>
              </Table>
            </div>

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

      {dialog ? (
        <StoreSettleDialog
          storeUuid={storeUuid}
          storeName={storeName}
          balance={dialog.balance}
          mode={dialog.mode}
          onClose={() => setDialog(null)}
        />
      ) : null}
    </div>
  );
}
