"use client";

import { useCallback, useEffect, useState } from "react";
import { useSearchParams } from "next/navigation";
import { RotateCcw, Wrench } from "lucide-react";
import { useTranslation } from "react-i18next";

import { useAsyncEffect } from "@/hooks/use-async-effect";
import { useTranslationRef } from "@/hooks/use-translation-ref";
import { toast } from "sonner";

import {
  getAdminPlayerWallets,
  getAdminTransferOrders,
  reverseTransferOrder,
  manuallyProcessTransferOrder,
  completeTransferInCredit,
} from "@/api/admin-wallet";
import { AdminDateRangeField } from "@/components/admin/admin-date-range-field";
import { AdminListPaginationFooter } from "@/components/admin/admin-list-pagination-footer";
import { AdminAgentIdentityCells, AdminAgentIdentityHeads } from "@/components/admin/admin-agent-columns";
import { AdminPlayerIdentityCells, AdminPlayerIdentityHeads } from "@/components/admin/admin-player-identity-columns";
import { AdminRowActionsMenu } from "@/components/admin/admin-row-actions-menu";
import { AdminTableExportButton } from "@/components/admin/admin-table-export-button";
import { AdminStatusBadge } from "@/components/admin/admin-status-badge";
import { Button } from "@/components/ui/button";
import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card";
import { Checkbox } from "@/components/ui/checkbox";
import { Input } from "@/components/ui/input";
import { Label } from "@/components/ui/label";
import { AdminTableNoResourceRow } from "@/components/admin/admin-no-resource-state";
import { AdminTableLoadingRow } from "@/components/admin/admin-loading-state";
import {
  Select,
  SelectContent,
  SelectItem,
  SelectTrigger,
  SelectValue,
} from "@/components/ui/select";
import {
  Table,
  TableBody,
  TableCell,
  TableHead,
  TableHeader,
  TableRow,
} from "@/components/ui/table";
import { adminHasAnyPermission } from "@/lib/admin-permissions";
import { PRD_WALLET_WRITE_ANY } from "@/lib/admin-prd";
import {
  canCompleteTransferInCredit,
  canManuallyProcessTransferOrder,
  canReverseTransferOrder,
} from "@/lib/wallet-transfer-actions";
import { useAdminProfile } from "@/stores/admin-session";
import { useAdminCurrencyCatalog } from "@/hooks/use-admin-currency-catalog";
import { useAdminDateTimeFormatter } from "@/hooks/use-admin-datetime-formatter";
import { useConfirmAction } from "@/hooks/use-confirm-action";
import { useExportLabels } from "@/hooks/use-export-labels";

import { AdminTableMoney, adminMoneyCellClassName } from "@/components/admin/admin-table-money";
import { formatAdminMinorUnits } from "@/lib/money";
import { WalletCellMonoId } from "@/modules/wallet/wallet-cell-mono-id";
import {
  TRANSFER_ORDER_STATUS_OPTIONS,
  WALLET_FILTER_ALL,
  emptyTransferFilters,
  transferFiltersFromSearchParams,
  walletAdminSelectDisplayedLabel,
  type TransferFilters,
} from "@/modules/wallet/wallet-filter-utils";
import { walletStatusLabel } from "@/modules/wallet/wallet-labels";
import { LotteryApiBizError } from "@/types/api/errors";
import type {
  AdminPlayerWalletsData,
  AdminTransferOrderItem,
  AdminTransferOrderListData,
} from "@/types/api/admin-wallet";

export { WalletTxnsPanel } from "@/modules/wallet/wallet-txns-panel";

type TransferOrderRowActionsProps = {
  row: AdminTransferOrderItem;
  canWriteWallet: boolean;
  busy: boolean;
  onCompleteCredit: (transferNo: string) => void;
  onReverse: (transferNo: string) => void;
  onManualProcess: (transferNo: string) => void;
  t: (key: string) => string;
};

function TransferOrderRowActions({
  row,
  canWriteWallet,
  busy,
  onCompleteCredit,
  onReverse,
  onManualProcess,
  t,
}: TransferOrderRowActionsProps): React.ReactElement {
  return (
    <AdminRowActionsMenu
      busy={busy}
      ariaLabel={t("actionsMenuAriaLabel")}
      actions={[
        {
          key: "complete",
          label: t("completeCredit"),
          hidden: !canCompleteTransferInCredit(row, canWriteWallet),
          onClick: () => onCompleteCredit(row.transfer_no),
        },
        {
          key: "manual",
          label: t("markCaseClosed"),
          icon: Wrench,
          hidden: !canManuallyProcessTransferOrder(row, canWriteWallet),
          onClick: () => onManualProcess(row.transfer_no),
        },
        {
          key: "reverse",
          label: t("reverse"),
          icon: RotateCcw,
          destructive: true,
          hidden: !canReverseTransferOrder(row, canWriteWallet),
          onClick: () => onReverse(row.transfer_no),
        },
      ]}
    />
  );
}

export function TransferOrdersPanel(): React.ReactElement {
  const { t } = useTranslation(["wallet", "common"]);
  const tRef = useTranslationRef(["wallet", "common"]);
  const { request: requestConfirm, ConfirmDialog } = useConfirmAction();
  const profile = useAdminProfile();
  const canWriteWallet = adminHasAnyPermission(profile?.permissions, [...PRD_WALLET_WRITE_ANY]);
  const exportLabels = useExportLabels("walletTransferOrders");
  useAdminCurrencyCatalog();
  const formatTs = useAdminDateTimeFormatter();
  const searchParams = useSearchParams();
  const urlFilterKey = searchParams.toString();
  const [data, setData] = useState<AdminTransferOrderListData | 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<TransferFilters>(() =>
    transferFiltersFromSearchParams(searchParams),
  );
  const [applied, setApplied] = useState<TransferFilters>(() =>
    transferFiltersFromSearchParams(searchParams),
  );
  const [actionLoading, setActionLoading] = useState<Set<string>>(new Set());

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

  const doAction = async (
    transferNo: string,
    fn: () => Promise<unknown>,
    successMsg: string,
  ) => {
    setActionLoading((prev) => new Set(prev).add(transferNo));
    try {
      await fn();
      toast.success(successMsg);
      void load();
    } catch (e) {
      toast.error(e instanceof LotteryApiBizError ? e.message : t("actionFailed"));
    } finally {
      setActionLoading((prev) => {
        const next = new Set(prev);
        next.delete(transferNo);
        return next;
      });
    }
  };

  const handleReverse = (transferNo: string) =>
    requestConfirm({
      title: t("confirm.reverseTitle"),
      description: t("confirm.reverseDescription", { transferNo }),
      confirmVariant: "destructive",
      onConfirm: () => doAction(transferNo, () => reverseTransferOrder(transferNo), t("reverseSuccess")),
    });

  const handleManuallyProcess = (transferNo: string) =>
    requestConfirm({
      title: t("confirm.markCaseClosedTitle"),
      description: t("confirm.markCaseClosedDescription", { transferNo }),
      onConfirm: () =>
        doAction(transferNo, () => manuallyProcessTransferOrder(transferNo), t("markCaseClosedSuccess")),
    });

  const handleCompleteCredit = (transferNo: string) =>
    requestConfirm({
      title: t("confirm.completeCreditTitle"),
      description: t("confirm.completeCreditDescription", { transferNo }),
      onConfirm: () =>
        doAction(transferNo, () => completeTransferInCredit(transferNo), t("completeCreditSuccess")),
    });

  const load = useCallback(async () => {
    setLoading(true);
    setErr(null);
    try {
      const player_id =
        applied.playerId.trim() === "" ? undefined : Number(applied.playerId);
      const d = await getAdminTransferOrders({
        page,
        per_page: perPage,
        abnormal: applied.abnormalOnly || undefined,
        player_id:
          player_id !== undefined && !Number.isNaN(player_id) && player_id > 0
            ? player_id
            : undefined,
        player_account: applied.playerAccount.trim() || undefined,
        transfer_no: applied.transferNo.trim() || undefined,
        external_ref_no: applied.externalRefNo.trim() || undefined,
        created_from: applied.createdFrom.trim() || undefined,
        created_to: applied.createdTo.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();
  }, [page, perPage, applied, tRef]);

  const runSearch = () => {
    setApplied({ ...draft });
    setPage(1);
  };

  const resetFilters = () => {
    setDraft(emptyTransferFilters);
    setApplied(emptyTransferFilters);
    setPage(1);
  };

  return (
    <>
    <Card>
      <CardHeader>
        <CardTitle>{t("transferOrders")}</CardTitle>
      </CardHeader>
      <CardContent className="space-y-4">
        {applied.abnormalOnly ? (
          <p className="rounded-md border border-amber-200/80 bg-amber-50 px-3 py-2 text-sm text-amber-950">
            {t("abnormalFilterActive")}
          </p>
        ) : null}
        <div className="grid gap-4 sm:grid-cols-2 lg:grid-cols-3 xl:grid-cols-4">
          <div className="grid gap-1.5">
            <Label htmlFor="to-transfer-no">{t("localTransferNo")}</Label>
            <Input
              id="to-transfer-no"
              placeholder={t("search")}
              value={draft.transferNo}
              onChange={(e) => setDraft((d) => ({ ...d, transferNo: e.target.value }))}
            />
          </div>
          <div className="grid gap-1.5">
            <Label htmlFor="to-ext">{t("externalRefNo")}</Label>
            <Input
              id="to-ext"
              placeholder={t("search")}
              value={draft.externalRefNo}
              onChange={(e) => setDraft((d) => ({ ...d, externalRefNo: e.target.value }))}
            />
          </div>
          <div className="grid gap-1.5">
            <Label htmlFor="to-account">{t("playerAccount")}</Label>
            <Input
              id="to-account"
              placeholder={t("playerAccountPlaceholder")}
              value={draft.playerAccount}
              onChange={(e) => setDraft((d) => ({ ...d, playerAccount: e.target.value }))}
            />
          </div>
          <div className="grid gap-1.5">
            <Label htmlFor="to-player">{t("playerId")}</Label>
            <Input
              id="to-player"
              inputMode="numeric"
              placeholder={t("playerIdOptional")}
              value={draft.playerId}
              onChange={(e) => setDraft((d) => ({ ...d, playerId: e.target.value }))}
            />
          </div>
          <div className="sm:col-span-2 lg:col-span-2 xl:col-span-2">
            <AdminDateRangeField
              id="to-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="grid gap-1.5">
            <Label htmlFor="to-status">{t("status")}</Label>
            <Select
              modal={false}
              value={
                draft.statusCsv === "" || !TRANSFER_ORDER_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="to-status" className="h-8 w-full">
                <SelectValue>
                  {(v) => walletAdminSelectDisplayedLabel(v, TRANSFER_ORDER_STATUS_OPTIONS, t)}
                </SelectValue>
              </SelectTrigger>
              <SelectContent align="start" sideOffset={6}>
                <SelectItem value={WALLET_FILTER_ALL}>{t("filterAll")}</SelectItem>
                {TRANSFER_ORDER_STATUS_OPTIONS.map((o) => (
                  <SelectItem key={o.value} value={o.value}>
                    {t(o.label)}
                  </SelectItem>
                ))}
              </SelectContent>
            </Select>
          </div>
          <div className="flex flex-col justify-end gap-2 sm:col-span-2 lg:col-span-1">
            <span className="text-sm font-medium leading-none">{t("options")}</span>
            <label className="flex min-h-9 cursor-pointer items-center gap-2 text-sm">
              <Checkbox
                checked={draft.abnormalOnly}
                onCheckedChange={(v) =>
                  setDraft((d) => ({ ...d, abnormalOnly: v === true }))
                }
              />
              {t("abnormalOnly")}
            </label>
          </div>
        </div>
        <div className="flex flex-wrap gap-2">
          <AdminTableExportButton
            tableId="wallet-transfer-orders-table"
            filename={exportLabels.filename}
            sheetName={exportLabels.sheetName}
          />
          <Button type="button" size="sm" onClick={() => runSearch()}>
            {t("search")}
          </Button>
          <Button type="button" size="sm" variant="outline" onClick={() => resetFilters()}>
            {t("resetFilters")}
          </Button>
          <Button type="button" size="sm" variant="secondary" onClick={() => void load()}>
            {t("refreshCurrentPage")}
          </Button>
        </div>

        {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-transfer-orders-table" className="min-w-[1180px]">
                <TableHeader>
                  <TableRow>
                    <TableHead className="min-w-0 max-w-[14rem]">{t("localTransferNo")}</TableHead>
                    <TableHead className="min-w-0 max-w-[12rem]">{t("externalRefNo")}</TableHead>
                    <AdminAgentIdentityHeads />
                    <AdminPlayerIdentityHeads />
                    <TableHead className="w-14">{t("direction")}</TableHead>
                    <TableHead className="whitespace-nowrap">{t("amount")}</TableHead>
                    <TableHead className="whitespace-nowrap">{t("status")}</TableHead>
                    <TableHead className="min-w-0 max-w-[14rem]">{t("failReason")}</TableHead>
                    <TableHead className="min-w-0 whitespace-normal leading-tight">{t("requestTime")}</TableHead>
                    <TableHead className="min-w-0 whitespace-normal leading-tight">{t("finishedTime")}</TableHead>
                    <TableHead className="sticky right-0 z-20 bg-muted w-12 text-center shadow-[-1px_0_0_rgba(203,213,225,0.7)]">{t("table.actions", { ns: "common" })}</TableHead>
                  </TableRow>
                </TableHeader>
                <TableBody>
                  {loading && !data ? (
                    <AdminTableLoadingRow colSpan={13} />
                  ) : !data || data.items.length === 0 ? (
                    <AdminTableNoResourceRow colSpan={13} />
                  ) : (
                    data.items.map((row) => (
                      <TableRow key={row.id}>
                        <TableCell className="min-w-0 max-w-[14rem] align-top whitespace-normal">
                          <WalletCellMonoId value={row.transfer_no} copyHint={t("copyTransferNo")} />
                        </TableCell>
                        <TableCell className="min-w-0 max-w-[12rem] align-top whitespace-normal">
                          <WalletCellMonoId value={row.external_ref_no} copyHint={t("copyExternalRefNo")} />
                        </TableCell>
                        <AdminAgentIdentityCells row={row} />
                        <AdminPlayerIdentityCells row={row} />
                        <TableCell>{row.direction}</TableCell>
                        <TableCell className={adminMoneyCellClassName("text-right")}>
                          <AdminTableMoney>
                            {formatAdminMinorUnits(row.amount, row.currency_code)}
                          </AdminTableMoney>
                        </TableCell>
                        <TableCell>
                          <AdminStatusBadge status={row.status}>{walletStatusLabel(row.status, t)}</AdminStatusBadge>
                        </TableCell>
                        <TableCell className="max-w-[14rem] whitespace-normal break-words text-xs text-muted-foreground">
                          {row.fail_reason?.trim() ? row.fail_reason : "—"}
                        </TableCell>
                        <TableCell className="min-w-0 whitespace-normal font-mono text-[11px] leading-snug text-muted-foreground">
                          {formatTs(row.created_at)}
                        </TableCell>
                        <TableCell className="min-w-0 whitespace-normal font-mono text-[11px] leading-snug text-muted-foreground">
                          {formatTs(row.finished_at)}
                        </TableCell>
                        <TableCell className="sticky right-0 z-10 bg-card text-center align-middle shadow-[-1px_0_0_rgba(203,213,225,0.7)]">
                          <div className="flex justify-center">
                            <TransferOrderRowActions
                              row={row}
                              canWriteWallet={canWriteWallet}
                              busy={actionLoading.has(row.transfer_no)}
                              onCompleteCredit={handleCompleteCredit}
                              onReverse={handleReverse}
                              onManualProcess={handleManuallyProcess}
                              t={t}
                            />
                          </div>
                        </TableCell>
                      </TableRow>
                    ))
                  )}
                </TableBody>
              </Table>
            </div>
            {data ? (
              <AdminListPaginationFooter
                selectId="wallet-transfer-orders-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}
      </CardContent>
    </Card>
    <ConfirmDialog />
    </>
  );
}

export function PlayerWalletPanel(): React.ReactElement {
  const { t } = useTranslation(["wallet", "common"]);
  const tRef = useTranslationRef(["wallet", "common"]);
  const exportLabels = useExportLabels("playerWallets");
  useAdminCurrencyCatalog();
  const [playerId, setPlayerId] = useState("");
  const [result, setResult] = useState<AdminPlayerWalletsData | null>(null);
  const [err, setErr] = useState<string | null>(null);
  const [loading, setLoading] = useState(false);

  const query = useCallback(async () => {
    const id = Number(playerId.trim());
    if (Number.isNaN(id) || id < 1) {
      setErr(tRef.current("invalidPlayerId"));
      setResult(null);
      return;
    }
    setLoading(true);
    setErr(null);
    try {
      const d = await getAdminPlayerWallets(id);
      setResult(d);
    } catch (e) {
      setErr(e instanceof LotteryApiBizError ? e.message : tRef.current("queryFailed"));
      setResult(null);
    } finally {
      setLoading(false);
    }
  }, [playerId, tRef]);

  return (
    <Card>
      <CardHeader>
        <CardTitle>{t("playerWalletQuery")}</CardTitle>
      </CardHeader>
      <CardContent className="space-y-4">
        <div className="flex flex-wrap items-end gap-2">
          <div className="grid gap-1.5">
            <Label htmlFor="pw-id">{t("playerId")}</Label>
            <Input
              id="pw-id"
              inputMode="numeric"
              placeholder="1"
              value={playerId}
              onChange={(e) => setPlayerId(e.target.value)}
              className="w-40"
            />
          </div>
          <AdminTableExportButton
            tableId="player-wallet-table"
            filename={exportLabels.filename}
            sheetName={exportLabels.sheetName}
          />
          <Button type="button" onClick={() => void query()} disabled={loading}>
            {loading ? t("querying") : t("query")}
          </Button>
        </div>
        {err ? <p className="text-sm text-destructive">{err}</p> : null}
        {result ? (
          <div className="space-y-3 rounded-lg border p-4 text-sm">
            <p>
              <span className="text-muted-foreground">{t("sitePlayer")}</span>{" "}
              {result.player.site_code}:{result.player.site_player_id}
            </p>
            <Table id="player-wallet-table">
              <TableHeader>
                <TableRow>
                  <TableHead>{t("walletType")}</TableHead>
                  <TableHead>{t("currency")}</TableHead>
                  <TableHead>{t("balanceMinor")}</TableHead>
                  <TableHead>{t("availableBalance")}</TableHead>
                </TableRow>
              </TableHeader>
              <TableBody>
                {result.wallets.length === 0 ? (
                  <AdminTableNoResourceRow colSpan={4} />
                ) : (
                  result.wallets.map((w) => (
                    <TableRow key={w.id}>
                      <TableCell>{w.wallet_type}</TableCell>
                      <TableCell>{w.currency_code}</TableCell>
                      <TableCell className={adminMoneyCellClassName("font-mono text-right")}>
                        <AdminTableMoney>{w.balance}</AdminTableMoney>
                      </TableCell>
                      <TableCell className={adminMoneyCellClassName("text-right")}>
                        <AdminTableMoney>
                          {formatAdminMinorUnits(w.available_balance, w.currency_code)}
                        </AdminTableMoney>
                      </TableCell>
                    </TableRow>
                  ))
                )}
              </TableBody>
            </Table>
          </div>
        ) : null}
      </CardContent>
    </Card>
  );
}
