"use client";

import { RefreshCw } from "lucide-react";
import { usePathname, useRouter, useSearchParams } from "next/navigation";
import { useCallback, useEffect, useState } from "react";
import { useTranslation } from "react-i18next";

import { getAdminWalletTransactions } from "@/api/admin-wallet";
import { AdminAgentIdentityCells, AdminAgentIdentityHeads } from "@/components/admin/admin-agent-columns";
import { AdminDateRangeField } from "@/components/admin/admin-date-range-field";
import { AdminListPaginationFooter } from "@/components/admin/admin-list-pagination-footer";
import { AdminTableLoadingRow } from "@/components/admin/admin-loading-state";
import { AdminTableNoResourceRow } from "@/components/admin/admin-no-resource-state";
import { AdminPlayerIdentityCells, AdminPlayerIdentityHeads } from "@/components/admin/admin-player-identity-columns";
import { AdminStatusBadge } from "@/components/admin/admin-status-badge";
import { AdminTableExportButton } from "@/components/admin/admin-table-export-button";
import { AdminTableMoney, adminMoneyCellClassName } from "@/components/admin/admin-table-money";
import { PlayerLedgerSourceBadge } from "@/components/admin/player-funding-badges";
import { Button } from "@/components/ui/button";
import { Checkbox } from "@/components/ui/checkbox";
import { Input } from "@/components/ui/input";
import { Label } from "@/components/ui/label";
import {
  Select,
  SelectContent,
  SelectItem,
  SelectTrigger,
  SelectValue,
} from "@/components/ui/select";
import {
  Table,
  TableBody,
  TableCell,
  TableHead,
  TableHeader,
  TableRow,
} from "@/components/ui/table";
import { useAsyncEffect } from "@/hooks/use-async-effect";
import { useAdminDateTimeFormatter } from "@/hooks/use-admin-datetime-formatter";
import { useExportLabels } from "@/hooks/use-export-labels";
import { useTranslationRef } from "@/hooks/use-translation-ref";
import { formatAdminMinorUnits } from "@/lib/money";
import { cn } from "@/lib/utils";
import { WalletCellMonoId } from "@/modules/wallet/wallet-cell-mono-id";
import {
  WALLET_FILTER_ALL,
  WALLET_TXN_BIZ_OPTIONS,
  WALLET_TXN_STATUS_OPTIONS,
  emptyTxnFilters,
  txnFiltersFromSearchParams,
  walletAdminSelectDisplayedLabel,
  type TxnFilters,
} from "@/modules/wallet/wallet-filter-utils";
import { walletStatusLabel, walletTxnBizTypeLabel } from "@/modules/wallet/wallet-labels";
import { LotteryApiBizError } from "@/types/api/errors";
import type { AdminWalletTxnListData } from "@/types/api/admin-wallet";

function parsePlayerId(raw: string): number | undefined {
  if (raw.trim() === "") {
    return undefined;
  }
  const id = Number(raw);
  return !Number.isNaN(id) && id > 0 ? id : undefined;
}

export function WalletTxnsPanel(): React.ReactElement {
  const { t } = useTranslation(["wallet", "common"]);
  const { t: tSettlement } = useTranslation("settlementCenter");
  const tRef = useTranslationRef(["wallet", "common"]);
  const exportLabels = useExportLabels("walletTransactions");
  const formatTs = useAdminDateTimeFormatter();
  const searchParams = useSearchParams();
  const urlFilterKey = searchParams.toString();
  const router = useRouter();
  const pathname = usePathname();

  const [data, setData] = useState<AdminWalletTxnListData | null>(null);
  const [loading, setLoading] = useState(true);
  const [err, setErr] = useState<string | null>(null);
  const [page, setPage] = useState(1);
  const [perPage, setPerPage] = useState(10);
  const [draft, setDraft] = useState<TxnFilters>(() => txnFiltersFromSearchParams(searchParams));
  const [applied, setApplied] = useState<TxnFilters>(() => txnFiltersFromSearchParams(searchParams));

  useEffect(() => {
    const next = txnFiltersFromSearchParams(searchParams);
    setDraft(next);
    setApplied(next);
    setPage(1);
  }, [urlFilterKey, searchParams]);

  const load = useCallback(async () => {
    setLoading(true);
    setErr(null);
    try {
      const d = await getAdminWalletTransactions({
        page,
        per_page: perPage,
        abnormal: applied.abnormalOnly || undefined,
        player_id: parsePlayerId(applied.playerId),
        player_account: applied.playerAccount.trim() || undefined,
        txn_no: applied.txnNo.trim() || undefined,
        external_ref_no: applied.externalRefNo.trim() || undefined,
        created_from: applied.createdFrom.trim() || undefined,
        created_to: applied.createdTo.trim() || undefined,
        biz_type: applied.bizType.trim() || undefined,
        status: applied.abnormalOnly ? undefined : applied.statusCsv.trim() || undefined,
      });
      setData(d);
    } catch (e) {
      setErr(e instanceof LotteryApiBizError ? e.message : tRef.current("loadFailed"));
      setData(null);
    } finally {
      setLoading(false);
    }
  }, [page, perPage, applied, tRef]);

  useAsyncEffect(() => {
    void load();
  }, [load]);

  const runSearch = () => {
    const next = draft.abnormalOnly ? { ...draft, statusCsv: "" } : { ...draft };
    setDraft(next);
    setApplied(next);
    setPage(1);
  };

  const resetFilters = () => {
    setDraft(emptyTxnFilters);
    setApplied(emptyTxnFilters);
    setPage(1);
    router.replace(pathname);
  };

  const showLedgerColumn = data?.items.some((row) => row.ledger_source === "credit_ledger") ?? false;
  const txnTableColSpan = showLedgerColumn ? 13 : 12;
  const hasDeepLink = applied.txnNo !== "" || applied.playerId !== "" || applied.externalRefNo !== "";

  return (
    <div className="flex w-full flex-col gap-4">
      <div className="rounded-lg border border-border/60">
        <div className="flex items-center justify-between gap-3 border-b border-border/60 px-3 py-2.5">
          <h2 className="text-sm font-semibold">{t("walletTransactions")}</h2>
          <div className="flex shrink-0 items-center gap-2">
            <AdminTableExportButton
              tableId="wallet-transactions-table"
              filename={exportLabels.filename}
              sheetName={exportLabels.sheetName}
            />
            <Button type="button" variant="ghost" size="sm" className="h-8" disabled={loading} onClick={() => void load()}>
              <RefreshCw className={cn("size-3.5", loading && "animate-spin")} />
              {t("refreshCurrentPage")}
            </Button>
          </div>
        </div>

        <div className="space-y-3 border-b border-border/60 px-3 py-3">
            <div className="grid gap-3 sm:grid-cols-2 lg:grid-cols-3 xl:grid-cols-4">
              <div className="grid gap-1.5">
                <Label htmlFor="tx-no" className="text-xs">
                  {t("txnNo")}
                </Label>
                <Input
                  id="tx-no"
                  className="h-8"
                  placeholder={t("search")}
                  value={draft.txnNo}
                  onChange={(e) => setDraft((d) => ({ ...d, txnNo: e.target.value }))}
                />
              </div>
              <div className="grid gap-1.5">
                <Label htmlFor="tx-ext" className="text-xs">
                  {t("externalRefNo")}
                </Label>
                <Input
                  id="tx-ext"
                  className="h-8"
                  placeholder={t("search")}
                  value={draft.externalRefNo}
                  onChange={(e) => setDraft((d) => ({ ...d, externalRefNo: e.target.value }))}
                />
              </div>
              <div className="grid gap-1.5">
                <Label htmlFor="tx-account" className="text-xs">
                  {t("playerAccount")}
                </Label>
                <Input
                  id="tx-account"
                  className="h-8"
                  placeholder={t("playerAccountPlaceholder")}
                  value={draft.playerAccount}
                  onChange={(e) => setDraft((d) => ({ ...d, playerAccount: e.target.value }))}
                />
              </div>
              <div className="grid gap-1.5">
                <Label htmlFor="tx-player" className="text-xs">
                  {t("playerId")}
                </Label>
                <Input
                  id="tx-player"
                  className="h-8"
                  inputMode="numeric"
                  placeholder={t("playerIdOptional")}
                  value={draft.playerId}
                  onChange={(e) => setDraft((d) => ({ ...d, playerId: e.target.value }))}
                />
              </div>
              <div className="grid gap-1.5">
                <Label htmlFor="tx-biz" className="text-xs">
                  {t("bizType")}
                </Label>
                <Select
                  modal={false}
                  value={
                    draft.bizType === "" || !WALLET_TXN_BIZ_OPTIONS.some((o) => o.value === draft.bizType)
                      ? WALLET_FILTER_ALL
                      : draft.bizType
                  }
                  onValueChange={(v) =>
                    setDraft((d) => ({
                      ...d,
                      bizType: v == null || v === WALLET_FILTER_ALL ? "" : String(v),
                    }))
                  }
                >
                  <SelectTrigger id="tx-biz" className="h-8 w-full">
                    <SelectValue>
                      {(v) => walletAdminSelectDisplayedLabel(v, WALLET_TXN_BIZ_OPTIONS, t)}
                    </SelectValue>
                  </SelectTrigger>
                  <SelectContent align="start" sideOffset={6}>
                    <SelectItem value={WALLET_FILTER_ALL}>{t("filterAll")}</SelectItem>
                    {WALLET_TXN_BIZ_OPTIONS.map((o) => (
                      <SelectItem key={o.value} value={o.value}>
                        {t(o.label)}
                      </SelectItem>
                    ))}
                  </SelectContent>
                </Select>
              </div>
              <div className="grid gap-1.5">
                <Label htmlFor="tx-status" className="text-xs">
                  {t("status")}
                </Label>
                <Select
                  modal={false}
                  disabled={draft.abnormalOnly}
                  value={
                    draft.statusCsv === "" || !WALLET_TXN_STATUS_OPTIONS.some((o) => o.value === draft.statusCsv)
                      ? WALLET_FILTER_ALL
                      : draft.statusCsv
                  }
                  onValueChange={(v) =>
                    setDraft((d) => ({
                      ...d,
                      statusCsv: v == null || v === WALLET_FILTER_ALL ? "" : String(v),
                    }))
                  }
                >
                  <SelectTrigger id="tx-status" className="h-8 w-full">
                    <SelectValue>
                      {(v) => walletAdminSelectDisplayedLabel(v, WALLET_TXN_STATUS_OPTIONS, t)}
                    </SelectValue>
                  </SelectTrigger>
                  <SelectContent align="start" sideOffset={6}>
                    <SelectItem value={WALLET_FILTER_ALL}>{t("filterAll")}</SelectItem>
                    {WALLET_TXN_STATUS_OPTIONS.map((o) => (
                      <SelectItem key={o.value} value={o.value}>
                        {t(o.label)}
                      </SelectItem>
                    ))}
                  </SelectContent>
                </Select>
              </div>
              <div className="sm:col-span-2 lg:col-span-2">
                <AdminDateRangeField
                  id="tx-created-range"
                  label={t("requestDateRange")}
                  from={draft.createdFrom}
                  to={draft.createdTo}
                  onRangeChange={(r) =>
                    setDraft((d) => ({ ...d, createdFrom: r.from, createdTo: r.to }))
                  }
                />
              </div>
              <div className="flex flex-col justify-end gap-2">
                <label className="flex min-h-8 cursor-pointer items-center gap-2 text-sm">
                  <Checkbox
                    checked={draft.abnormalOnly}
                    onCheckedChange={(v) => {
                      const abnormalOnly = v === true;
                      setDraft((d) => ({
                        ...d,
                        abnormalOnly,
                        statusCsv: abnormalOnly ? "" : d.statusCsv,
                      }));
                    }}
                  />
                  {t("abnormalOnlyPending")}
                </label>
              </div>
            </div>
            <div className="flex flex-wrap gap-2">
              <Button type="button" size="sm" className="h-8" onClick={() => runSearch()}>
                {t("search")}
              </Button>
              <Button type="button" size="sm" variant="outline" className="h-8" onClick={() => resetFilters()}>
                {t("resetFilters")}
              </Button>
            </div>
        </div>

        <div className="space-y-3 p-3">
          {applied.abnormalOnly ? (
            <p className="rounded-md border border-amber-200/80 bg-amber-50 px-3 py-2 text-sm text-amber-950">
              {t("txnAbnormalFilterActive")}
            </p>
          ) : null}
          {hasDeepLink ? (
            <p className="rounded-md border border-border/60 bg-muted/30 px-3 py-2 text-sm text-muted-foreground">
              {t("txnDeepLinkActive")}
            </p>
          ) : null}

          {err ? <p className="text-sm text-destructive">{err}</p> : null}
          {(loading && !data) || data ? (
            <>
              <div className="admin-table-shell overflow-x-auto rounded-md border">
                <Table id="wallet-transactions-table" className="min-w-[1080px]">
                  <TableHeader>
                    <TableRow>
                      <TableHead className="min-w-[9.5rem]">{t("txnNo")}</TableHead>
                      <TableHead className="min-w-[8rem]">{t("externalRefNo")}</TableHead>
                      <AdminAgentIdentityHeads />
                      <AdminPlayerIdentityHeads />
                      {showLedgerColumn ? (
                        <TableHead className="whitespace-nowrap">{t("ledgerChannel")}</TableHead>
                      ) : null}
                      <TableHead className="min-w-[6rem]">{t("type")}</TableHead>
                      <TableHead className="min-w-[5.5rem] text-right">{t("amount")}</TableHead>
                      <TableHead className="min-w-[4rem] text-center">{t("direction")}</TableHead>
                      <TableHead className="whitespace-nowrap">{t("status")}</TableHead>
                      <TableHead className="min-w-[8rem] whitespace-nowrap">{t("requestTime")}</TableHead>
                      <TableHead className="min-w-[8rem] whitespace-nowrap">{t("finishedTime")}</TableHead>
                    </TableRow>
                  </TableHeader>
                  <TableBody>
                    {loading && !data ? (
                      <AdminTableLoadingRow colSpan={txnTableColSpan} />
                    ) : !data || data.items.length === 0 ? (
                      <AdminTableNoResourceRow colSpan={txnTableColSpan} />
                    ) : (
                      data.items.map((row) => (
                        <TableRow key={`${row.ledger_source ?? "wallet"}-${row.id}`}>
                          <TableCell className="align-middle">
                            <WalletCellMonoId value={row.txn_no} copyHint={t("copyTxnNo")} />
                          </TableCell>
                          <TableCell className="align-middle">
                            <WalletCellMonoId value={row.external_ref_no} copyHint={t("copyExternalTxnRefNo")} />
                          </TableCell>
                          <AdminAgentIdentityCells row={row} />
                          <AdminPlayerIdentityCells row={row} />
                          {showLedgerColumn ? (
                            <TableCell className="align-middle whitespace-nowrap">
                              <PlayerLedgerSourceBadge ledgerSource={row.ledger_source} />
                            </TableCell>
                          ) : null}
                          <TableCell className="align-middle text-xs">
                            <span
                              className="line-clamp-2"
                              title={walletTxnBizTypeLabel(row.biz_type, row.ledger_source, t, tSettlement)}
                            >
                              {walletTxnBizTypeLabel(row.biz_type, row.ledger_source, t, tSettlement)}
                            </span>
                          </TableCell>
                          <TableCell className={adminMoneyCellClassName("align-middle text-right text-xs")}>
                            <AdminTableMoney>
                              {row.amount_formatted ?? formatAdminMinorUnits(row.amount)}
                            </AdminTableMoney>
                          </TableCell>
                          <TableCell className="align-middle text-center text-xs text-muted-foreground">
                            {row.direction === 1 ? t("in") : t("out")}
                          </TableCell>
                          <TableCell className="align-middle whitespace-nowrap">
                            <AdminStatusBadge status={row.status}>{walletStatusLabel(row.status, t)}</AdminStatusBadge>
                          </TableCell>
                          <TableCell className="align-middle whitespace-nowrap font-mono text-xs text-muted-foreground">
                            {formatTs(row.created_at)}
                          </TableCell>
                          <TableCell className="align-middle whitespace-nowrap font-mono text-xs text-muted-foreground">
                            {formatTs(row.updated_at)}
                          </TableCell>
                        </TableRow>
                      ))
                    )}
                  </TableBody>
                </Table>
              </div>
              {data ? (
                <AdminListPaginationFooter
                  selectId="wallet-transactions-per-page"
                  total={data.total}
                  page={page}
                  lastPage={Math.max(1, Math.ceil(data.total / Math.max(1, data.per_page)))}
                  perPage={perPage}
                  loading={loading}
                  onPerPageChange={(next) => {
                    setPerPage(next);
                    setPage(1);
                  }}
                  onPageChange={setPage}
                />
              ) : null}
            </>
          ) : null}
        </div>
      </div>
    </div>
  );
}