"use client";

import { isAxiosError } from "axios";
import { Loader2 } from "lucide-react";
import { useMemo, useRef, useState, type ReactNode } from "react";
import { useTranslation } from "react-i18next";
import { toast } from "sonner";

import { postWalletTransferIn, postWalletTransferOut } from "@/api/wallet";
import { Button } from "@/components/ui/button";
import {
  Card,
  CardContent,
  CardDescription,
  CardHeader,
  CardTitle,
} from "@/components/ui/card";
import { Input } from "@/components/ui/input";
import { Label } from "@/components/ui/label";
import { PlayerPanel } from "@/components/layout/player-panel";
import {
  formatMinorAsCurrency,
  getCurrencyDecimalPlaces,
  parseDecimalInputToMinor,
} from "@/lib/money";
import { useCurrencyCatalog } from "@/hooks/use-currency-catalog";
import { randomIdempotentKey } from "@/lib/utils";
import { formatWalletClientError } from "@/lib/wallet-api-error";
import { LotteryApiBizError } from "@/types/api/errors";

/** 处理中 / 待对账：刷新数据后提示用文案即可 */
function emitWalletRefresh() {
  if (typeof window !== "undefined") {
    window.dispatchEvent(new Event("lottery-wallet-refresh"));
  }
}

async function handleTransferMaybePending(
  e: unknown,
  onRefresh: () => Promise<void>,
  t: (key: string) => string,
): Promise<boolean> {
  if (e instanceof LotteryApiBizError && e.code === 1002) {
    toast.message(e.message || t("wallet.pendingToast"));
    await onRefresh();
    emitWalletRefresh();
    return true;
  }
  if (isAxiosError(e) && e.response?.status === 409) {
    toast.message(t("wallet.pendingShort"));
    await onRefresh();
    emitWalletRefresh();
    return true;
  }
  return false;
}

type PanelBase = {
  currency: string;
  idPrefix?: string;
  /** 提交成功后刷新余额等 */
  onSuccess: () => Promise<void>;
};

type PanelVariant = "dialog" | "page";

function TransferInfoBlock({ children }: { children: ReactNode }) {
  return (
    <div className="rounded-lg border border-border bg-muted/40 px-3 py-2.5 text-sm leading-relaxed">
      {children}
    </div>
  );
}

function TransferPreview({ children }: { children: ReactNode }) {
  return (
    <p className="rounded-lg bg-muted/50 px-3 py-2 text-sm text-muted-foreground">{children}</p>
  );
}

function TransferError({ message }: { message: string }) {
  return (
    <p className="rounded-lg border border-destructive/30 bg-destructive/10 px-3 py-2 text-sm text-destructive">
      {message}
    </p>
  );
}

function TransferDialogFooter({
  submitting,
  confirmLabel,
  onConfirm,
  onCancel,
}: {
  submitting: boolean;
  confirmLabel: string;
  onConfirm: () => void;
  onCancel: () => void;
}) {
  const { t } = useTranslation("player");

  return (
    <div className="mt-5 grid gap-2">
      <Button
        type="button"
        size="lg"
        className="h-11 w-full bg-[#07459f] text-base font-semibold text-white hover:bg-[#063b88]"
        disabled={submitting}
        onClick={onConfirm}
      >
        {submitting ? (
          <>
            <Loader2 className="mr-2 size-4 animate-spin" />
            {t("actions.processing")}
          </>
        ) : (
          confirmLabel
        )}
      </Button>
      <Button
        type="button"
        variant="outline"
        size="lg"
        className="h-10 w-full"
        disabled={submitting}
        onClick={onCancel}
      >
        {t("actions.cancel")}
      </Button>
    </div>
  );
}

/** 弹窗内：取消关闭；独立页：仅展示提交（返回用顶栏或上方链接） */
export function TransferInPanel({
  currency,
  lotteryMinor,
  mainMinor = null,
  onSuccess,
  idPrefix = "",
  onCancel,
  variant = "dialog",
}: PanelBase & {
  lotteryMinor: number;
  mainMinor?: number | null;
  onCancel: () => void;
  variant?: PanelVariant;
}) {
  const { t } = useTranslation("player");
  useCurrencyCatalog();
  const [amountText, setAmountText] = useState("");
  const [submitting, setSubmitting] = useState(false);
  const [localError, setLocalError] = useState<string | null>(null);
  const idempotentKeyRef = useRef<string | null>(null);
  const tid = `${idPrefix}in-amount`;

  const parsedMinor = useMemo(
    () => parseDecimalInputToMinor(amountText, currency),
    [amountText, currency],
  );
  const previewAfter =
    parsedMinor != null ? lotteryMinor + parsedMinor : lotteryMinor;

  const submit = async () => {
    if (submitting) {
      return;
    }
    setLocalError(null);
    if (parsedMinor == null || parsedMinor < 1) {
      setLocalError(t("wallet.invalidAmount"));
      return;
    }
    if (idempotentKeyRef.current === null) {
      idempotentKeyRef.current = randomIdempotentKey();
    }
    setSubmitting(true);
    try {
      await postWalletTransferIn({
        amount: parsedMinor,
        currency,
        idempotent_key: idempotentKeyRef.current,
      });
      idempotentKeyRef.current = null;
      toast.success(t("wallet.successIn"));
      setAmountText("");
      await onSuccess();
      emitWalletRefresh();
    } catch (e) {
      if (await handleTransferMaybePending(e, onSuccess, t)) {
        return;
      }
      setLocalError(formatWalletClientError(e, t));
    } finally {
      setSubmitting(false);
    }
  };

  const footer =
    variant === "page" ? (
      <Button
        type="button"
        size="lg"
        className="mt-5 h-11 w-full bg-[#07459f] text-base font-semibold text-white hover:bg-[#063b88]"
        disabled={submitting}
        onClick={() => void submit()}
      >
        {submitting ? (
          <>
            <Loader2 className="mr-2 size-4 animate-spin" />
            {t("actions.processing")}
          </>
        ) : (
          t("wallet.confirmIn")
        )}
      </Button>
    ) : (
      <TransferDialogFooter
        submitting={submitting}
        confirmLabel={t("wallet.confirmIn")}
        onConfirm={() => void submit()}
        onCancel={onCancel}
      />
    );

  return (
    <>
      <div className="grid gap-3">
        <TransferInfoBlock>
          <p className="text-muted-foreground">
            {t("wallet.mainBalance")}{" "}
            <span className="font-medium tabular-nums text-foreground">
              {mainMinor != null
                ? formatMinorAsCurrency(mainMinor, currency)
                : t("wallet.mainPending")}
            </span>
          </p>
          <p className="mt-2 text-muted-foreground">
            {t("wallet.lotteryBalance")}{" "}
            <span className="font-semibold tabular-nums text-foreground">
              {formatMinorAsCurrency(lotteryMinor, currency)}
            </span>
          </p>
        </TransferInfoBlock>
        <div className="grid gap-2">
          <Label htmlFor={tid}>{t("wallet.inAmount")}</Label>
          <Input
            id={tid}
            inputMode="decimal"
            placeholder={t("wallet.exampleIn")}
            value={amountText}
            onChange={(ev) => setAmountText(ev.target.value)}
            disabled={submitting}
            autoComplete="off"
            className="h-11 text-base tabular-nums"
          />
          <TransferPreview>
            {t("wallet.afterInPreview", {
              amount: formatMinorAsCurrency(previewAfter, currency),
            })}
          </TransferPreview>
        </div>
        {localError ? <TransferError message={localError} /> : null}
      </div>
      {footer}
    </>
  );
}

export function TransferOutPanel({
  currency,
  availableMinor,
  onSuccess,
  idPrefix = "",
  onCancel,
  variant = "dialog",
}: PanelBase & {
  availableMinor: number;
  onCancel: () => void;
  variant?: PanelVariant;
}) {
  const { t } = useTranslation("player");
  useCurrencyCatalog();
  const [amountText, setAmountText] = useState("");
  const [submitting, setSubmitting] = useState(false);
  const [localError, setLocalError] = useState<string | null>(null);
  const idempotentKeyRef = useRef<string | null>(null);
  const tid = `${idPrefix}out-amount`;

  const parsedMinor = useMemo(
    () => parseDecimalInputToMinor(amountText, currency),
    [amountText, currency],
  );
  const previewAfter =
    parsedMinor != null
      ? Math.max(0, availableMinor - parsedMinor)
      : availableMinor;

  const fillAll = () => {
    const decimals = getCurrencyDecimalPlaces(currency);
    const major = availableMinor / 10 ** decimals;
    setAmountText(major.toFixed(decimals));
  };

  const submit = async () => {
    if (submitting) {
      return;
    }
    setLocalError(null);
    if (parsedMinor == null || parsedMinor < 1) {
      setLocalError(t("wallet.invalidAmount"));
      return;
    }
    if (parsedMinor > availableMinor) {
      setLocalError(t("wallet.outExceeds"));
      return;
    }
    if (idempotentKeyRef.current === null) {
      idempotentKeyRef.current = randomIdempotentKey();
    }
    setSubmitting(true);
    try {
      await postWalletTransferOut({
        amount: parsedMinor,
        currency,
        idempotent_key: idempotentKeyRef.current,
      });
      idempotentKeyRef.current = null;
      toast.success(t("wallet.successOut"));
      setAmountText("");
      await onSuccess();
      emitWalletRefresh();
    } catch (e) {
      if (await handleTransferMaybePending(e, onSuccess, t)) {
        return;
      }
      setLocalError(formatWalletClientError(e, t));
    } finally {
      setSubmitting(false);
    }
  };

  const footer =
    variant === "page" ? (
      <Button
        type="button"
        size="lg"
        className="mt-5 h-11 w-full bg-[#07459f] text-base font-semibold text-white hover:bg-[#063b88]"
        disabled={submitting}
        onClick={() => void submit()}
      >
        {submitting ? (
          <>
            <Loader2 className="mr-2 size-4 animate-spin" />
            {t("actions.processing")}
          </>
        ) : (
          t("wallet.confirmOut")
        )}
      </Button>
    ) : (
      <TransferDialogFooter
        submitting={submitting}
        confirmLabel={t("wallet.confirmOut")}
        onConfirm={() => void submit()}
        onCancel={onCancel}
      />
    );

  return (
    <>
      <div className="grid gap-3">
        <TransferInfoBlock>
          <p className="text-muted-foreground">
            {t("wallet.lotteryAvailable")}{" "}
            <span className="font-semibold tabular-nums text-foreground">
              {formatMinorAsCurrency(availableMinor, currency)}
            </span>
          </p>
        </TransferInfoBlock>
        <div className="grid gap-2">
          <div className="flex items-center justify-between gap-2">
            <Label htmlFor={tid}>{t("wallet.outAmount")}</Label>
            <Button
              type="button"
              variant="link"
              className="h-auto p-0 text-sm font-medium"
              onClick={fillAll}
              disabled={submitting || availableMinor < 1}
            >
              {t("wallet.allOut", {
                amount: formatMinorAsCurrency(availableMinor, currency),
              })}
            </Button>
          </div>
          <Input
            id={tid}
            inputMode="decimal"
            placeholder={t("wallet.exampleOut")}
            value={amountText}
            onChange={(ev) => setAmountText(ev.target.value)}
            disabled={submitting}
            autoComplete="off"
            className="h-11 text-base tabular-nums"
          />
          <TransferPreview>
            {t("wallet.afterOutPreview", {
              amount: formatMinorAsCurrency(previewAfter, currency),
            })}
          </TransferPreview>
        </div>
        {localError ? <TransferError message={localError} /> : null}
      </div>
      {footer}
    </>
  );
}

/** 独立路由页：转入（仅组合 Card + Panel） */
export function TransferInPage({
  currency,
  lotteryMinor,
  mainMinor = null,
  onSuccess,
}: PanelBase & { lotteryMinor: number; mainMinor?: number | null }) {
  const { t } = useTranslation("player");

  return (
    <PlayerPanel
      title={t("wallet.transferInTitle")}
      backHref="/wallet"
      backLabel={t("wallet.title")}
    >
      <Card>
        <CardHeader>
          <CardTitle>{t("wallet.transferInTitle")}</CardTitle>
          <CardDescription>{t("wallet.transferInDescription")}</CardDescription>
        </CardHeader>
        <CardContent>
          <TransferInPanel
            variant="page"
            currency={currency}
            lotteryMinor={lotteryMinor}
            mainMinor={mainMinor}
            idPrefix="page-"
            onSuccess={onSuccess}
            onCancel={() => {}}
          />
        </CardContent>
      </Card>
    </PlayerPanel>
  );
}

/** 独立路由页：转出 */
export function TransferOutPage({
  currency,
  availableMinor,
  onSuccess,
}: PanelBase & { availableMinor: number }) {
  const { t } = useTranslation("player");

  return (
    <PlayerPanel
      title={t("wallet.transferOutTitle")}
      backHref="/wallet"
      backLabel={t("wallet.title")}
    >
      <Card>
        <CardHeader>
          <CardTitle>{t("wallet.transferOutTitle")}</CardTitle>
          <CardDescription>{t("wallet.transferOutDescription")}</CardDescription>
        </CardHeader>
        <CardContent>
          <TransferOutPanel
            variant="page"
            currency={currency}
            availableMinor={availableMinor}
            idPrefix="page-"
            onSuccess={onSuccess}
            onCancel={() => {}}
          />
        </CardContent>
      </Card>
    </PlayerPanel>
  );
}
