"use client";

import { useCallback, useState } from "react";
import { useTranslation } from "react-i18next";
import { useAsyncEffect } from "@/hooks/use-async-effect";
import { useTranslationRef } from "@/hooks/use-translation-ref";

import {
  getAdminJackpotPoolAdjustments,
  getAdminJackpotPools,
  postAdminJackpotManualBurst,
  postAdminJackpotPoolAdjustment,
  putAdminJackpotPool,
} from "@/api/admin-jackpot";
import { useAdminPlayTypeCatalog } from "@/hooks/use-admin-play-type-catalog";
import { useCachedPlayTypeOptions } from "@/hooks/use-cached-play-type-options";
import { useConfirmAction } from "@/hooks/use-confirm-action";
import { adminHasAnyPermission } from "@/lib/admin-permissions";
import { formatAdminMinorDecimal, parseAdminMajorToMinor } from "@/lib/money";
import { PRD_JACKPOT_MANAGE, PRD_JACKPOT_MANUAL_BURST } from "@/lib/admin-prd";
import { AdminPageCard } from "@/components/admin/admin-page-card";
import { AdminNoResourceState } from "@/components/admin/admin-no-resource-state";
import { ModuleScaffold } from "@/components/admin/module-scaffold";
import { Button } from "@/components/ui/button";
import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card";
import { Input } from "@/components/ui/input";
import { Label } from "@/components/ui/label";
import { Checkbox } from "@/components/ui/checkbox";
import { Switch } from "@/components/ui/switch";
import {
  Dialog,
  DialogContent,
  DialogDescription,
  DialogFooter,
  DialogHeader,
  DialogTitle,
} from "@/components/ui/dialog";
import { toast } from "sonner";
import { useAdminProfile } from "@/stores/admin-session";
import { LotteryApiBizError } from "@/types/api/errors";
import type { AdminJackpotPoolAdjustmentRow, AdminJackpotPoolRow } from "@/types/api/admin-jackpot";
import {
  Select,
  SelectContent,
  SelectItem,
  SelectTrigger,
  SelectValue,
} from "@/components/ui/select";
import { Textarea } from "@/components/ui/textarea";
import { AdminLoadingState } from "@/components/admin/admin-loading-state";
import { percentUiToRatio, ratioToPercentUi } from "@/lib/admin-rate-percent";

type Draft = {
  contribution_rate: string;
  trigger_threshold: string;
  payout_rate: string;
  force_trigger_draw_gap: string;
  min_bet_amount: string;
  combo_trigger_play_codes: string[];
  status: string;
  manual_burst_draw_id: string;
};

type AdjustmentDraft = {
  direction: "increase" | "decrease";
  amount: string;
  reason: string;
};

function toDraft(p: AdminJackpotPoolRow): Draft {
  return {
    contribution_rate: ratioToPercentUi(p.contribution_rate),
    trigger_threshold: formatAdminMinorDecimal(p.trigger_threshold, p.currency_code),
    payout_rate: ratioToPercentUi(p.payout_rate),
    force_trigger_draw_gap: String(p.force_trigger_draw_gap),
    min_bet_amount: formatAdminMinorDecimal(p.min_bet_amount, p.currency_code),
    combo_trigger_play_codes: p.combo_trigger_play_codes.map((code) => code.toLowerCase()),
    status: String(p.status),
    manual_burst_draw_id: "",
  };
}

type JackpotPoolsConsoleProps = {
  embedded?: boolean;
};

export function JackpotPoolsConsole({ embedded = false }: JackpotPoolsConsoleProps) {
  const { t } = useTranslation(["jackpot", "common"]);
  const tRef = useTranslationRef(["jackpot", "common"]);
  useAdminPlayTypeCatalog();
  const playOptions = useCachedPlayTypeOptions();
  const profile = useAdminProfile();
  const canManageJackpot = adminHasAnyPermission(profile?.permissions, [PRD_JACKPOT_MANAGE]);
  const canManualBurst = adminHasAnyPermission(profile?.permissions, [PRD_JACKPOT_MANUAL_BURST]);
  const { request: requestConfirm, ConfirmDialog: ConfirmActionDialog } = useConfirmAction();
  const [items, setItems] = useState<AdminJackpotPoolRow[]>([]);
  const [drafts, setDrafts] = useState<Record<number, Draft>>({});
  const [loading, setLoading] = useState(true);
  const [savingId, setSavingId] = useState<number | null>(null);
  const [burstingId, setBurstingId] = useState<number | null>(null);
  const [confirmBurstPoolId, setConfirmBurstPoolId] = useState<number | null>(null);
  const [adjustmentDrafts, setAdjustmentDrafts] = useState<Record<number, AdjustmentDraft>>({});
  const [adjustmentRows, setAdjustmentRows] = useState<Record<number, AdminJackpotPoolAdjustmentRow[]>>({});
  const [adjustingId, setAdjustingId] = useState<number | null>(null);
  const [adjustmentOpenId, setAdjustmentOpenId] = useState<number | null>(null);

  const load = useCallback(async () => {
    setLoading(true);
    try {
      const res = await getAdminJackpotPools();
      setItems(res.items);
      const d: Record<number, Draft> = {};
      const adjDrafts: Record<number, AdjustmentDraft> = {};
      for (const p of res.items) {
        d[p.id] = toDraft(p);
        adjDrafts[p.id] = { direction: "increase", amount: "", reason: "" };
      }
      setDrafts(d);
      setAdjustmentDrafts(adjDrafts);
    } catch (e) {
      toast.error(e instanceof LotteryApiBizError ? e.message : tRef.current("loadFailed"));
    } finally {
      setLoading(false);
    }
  }, [tRef]);

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

  const loadAdjustments = useCallback(async (poolId: number) => {
    try {
      const ledger = await getAdminJackpotPoolAdjustments(poolId, { per_page: 5 });
      setAdjustmentRows((prev) => ({ ...prev, [poolId]: ledger.items }));
    } catch {
      setAdjustmentRows((prev) => ({ ...prev, [poolId]: [] }));
    }
  }, []);

  const updateDraft = (id: number, patch: Partial<Draft>) => {
    setDrafts((prev) => ({
      ...prev,
      [id]: { ...prev[id], ...patch },
    }));
  };

  const toggleComboPlay = (poolId: number, code: string, checked: boolean) => {
    const normalized = code.toLowerCase();
    const current = drafts[poolId]?.combo_trigger_play_codes ?? [];
    const next = checked
      ? [...new Set([...current, normalized])]
      : current.filter((item) => item !== normalized);
    updateDraft(poolId, { combo_trigger_play_codes: next });
  };

  const updateAdjustmentDraft = (id: number, patch: Partial<AdjustmentDraft>) => {
    setAdjustmentDrafts((prev) => ({
      ...prev,
      [id]: { ...(prev[id] ?? { direction: "increase", amount: "", reason: "" }), ...patch },
    }));
  };

  const toggleAdjustment = (poolId: number, open: boolean) => {
    setAdjustmentOpenId(open ? poolId : null);
    if (open && adjustmentRows[poolId] === undefined) {
      void loadAdjustments(poolId);
    }
  };

  const save = async (p: AdminJackpotPoolRow) => {
    const d = drafts[p.id];
    if (!d) return;
    setSavingId(p.id);
    try {
      await putAdminJackpotPool(p.id, {
        contribution_rate: percentUiToRatio(d.contribution_rate),
        trigger_threshold: parseAdminMajorToMinor(d.trigger_threshold, p.currency_code) ?? 0,
        payout_rate: percentUiToRatio(d.payout_rate),
        force_trigger_draw_gap: Number.parseInt(d.force_trigger_draw_gap, 10),
        min_bet_amount: parseAdminMajorToMinor(d.min_bet_amount, p.currency_code) ?? 0,
        combo_trigger_play_codes: d.combo_trigger_play_codes,
        status: Number.parseInt(d.status, 10),
      });
      toast.success(t("saveSuccess"));
      await load();
    } catch (e) {
      toast.error(e instanceof LotteryApiBizError ? e.message : t("saveFailed"));
    } finally {
      setSavingId(null);
    }
  };

  const submitAdjustment = async (p: AdminJackpotPoolRow) => {
    const adj = adjustmentDrafts[p.id];
    if (!adj) return;
    const minor = parseAdminMajorToMinor(adj.amount, p.currency_code);
    if (minor === null || minor <= 0) {
      toast.error(t("adjustmentAmountInvalid"));
      return;
    }
    const trimmedReason = adj.reason.trim();
    if (trimmedReason.length < 3) {
      toast.error(t("adjustmentReasonRequired"));
      return;
    }
    const amountDelta = adj.direction === "decrease" ? -minor : minor;

    setAdjustingId(p.id);
    try {
      const res = await postAdminJackpotPoolAdjustment(p.id, {
        amount_delta: amountDelta,
        reason: trimmedReason,
      });
      toast.success(t("adjustmentSuccess"));
      setItems((prev) =>
        prev.map((row) =>
          row.id === p.id ? { ...row, current_amount: res.pool.current_amount } : row,
        ),
      );
      updateAdjustmentDraft(p.id, { amount: "", reason: "" });
      await loadAdjustments(p.id);
    } catch (e) {
      toast.error(e instanceof LotteryApiBizError ? e.message : t("adjustmentFailed"));
    } finally {
      setAdjustingId(null);
    }
  };

  const manualBurst = async (p: AdminJackpotPoolRow) => {
    const d = drafts[p.id];
    if (!d) return;
    const drawRef = d.manual_burst_draw_id.trim();
    if (drawRef.length === 0) {
      toast.error(t("invalidDrawId"));
      return;
    }

    setBurstingId(p.id);
    try {
      const res = await postAdminJackpotManualBurst(p.id, { draw_id: drawRef });
      toast.success(
        `${t("manualBurstSuccess")} · ${res.draw_no} · ${res.winner_count} ${t("winnerCount")}`,
      );
      await load();
    } catch (e) {
      toast.error(e instanceof LotteryApiBizError ? e.message : t("manualBurstFailed"));
    } finally {
      setBurstingId(null);
      setConfirmBurstPoolId(null);
    }
  };

  const poolList = (
    <div className={embedded ? "space-y-4" : "space-y-6"}>
      {loading ? <AdminLoadingState minHeight="6rem" className="py-6" /> : null}
      {!loading && items.length === 0 ? <AdminNoResourceState /> : null}
      {items.map((p) => {
        const d = drafts[p.id] ?? toDraft(p);
        const adj = adjustmentDrafts[p.id] ?? { direction: "increase", amount: "", reason: "" };
        const ledger = adjustmentRows[p.id] ?? [];
        const currentAmount = formatAdminMinorDecimal(p.current_amount, p.currency_code);
        const statusOn = d.status === "1";
        const adjustmentOpen = adjustmentOpenId === p.id;

        return (
          <AdminPageCard
            key={p.id}
            title={p.currency_code}
            actions={
              <div className="flex flex-wrap items-center gap-2">
                <div className="flex items-center gap-2">
                  <Label htmlFor={`status-${p.id}`} className="text-sm text-muted-foreground">
                    {t("status")}
                  </Label>
                  <Switch
                    id={`status-${p.id}`}
                    checked={statusOn}
                    disabled={!canManageJackpot}
                    aria-label={t("status")}
                    onCheckedChange={(checked) => updateDraft(p.id, { status: checked ? "1" : "0" })}
                  />
                </div>
                {canManageJackpot ? (
                  <Button
                    type="button"
                    size="sm"
                    disabled={savingId === p.id}
                    onClick={() =>
                      requestConfirm({
                        title: t("confirmSavePoolTitle"),
                        description: t("confirmSavePoolDescription"),
                        confirmLabel: t("confirm.confirmSave", { ns: "common" }),
                        onConfirm: () => save(p),
                      })
                    }
                  >
                    {savingId === p.id ? t("saving") : t("save")}
                  </Button>
                ) : null}
              </div>
            }
          >
            <p className="mb-4 text-2xl font-semibold tabular-nums tracking-tight">{currentAmount}</p>

            <fieldset disabled={!canManageJackpot} className="grid gap-3 sm:grid-cols-2 lg:grid-cols-3">
              <div className="space-y-1.5">
                <Label htmlFor={`cr-${p.id}`}>{t("contributionRate")}</Label>
                <Input
                  id={`cr-${p.id}`}
                  type="number"
                  min={0}
                  max={100}
                  step="0.01"
                  className="font-mono"
                  value={d.contribution_rate}
                  onChange={(e) => updateDraft(p.id, { contribution_rate: e.target.value })}
                />
              </div>
              <div className="space-y-1.5">
                <Label htmlFor={`th-${p.id}`}>{t("triggerThreshold")}</Label>
                <Input
                  id={`th-${p.id}`}
                  className="font-mono"
                  value={d.trigger_threshold}
                  onChange={(e) => updateDraft(p.id, { trigger_threshold: e.target.value })}
                />
              </div>
              <div className="space-y-1.5">
                <Label htmlFor={`pr-${p.id}`}>{t("payoutRate")}</Label>
                <Input
                  id={`pr-${p.id}`}
                  type="number"
                  min={0}
                  max={100}
                  step="0.01"
                  className="font-mono"
                  value={d.payout_rate}
                  onChange={(e) => updateDraft(p.id, { payout_rate: e.target.value })}
                />
              </div>
              <div className="space-y-1.5">
                <Label htmlFor={`min-${p.id}`}>{t("minBetAmount")}</Label>
                <Input
                  id={`min-${p.id}`}
                  className="font-mono"
                  value={d.min_bet_amount}
                  onChange={(e) => updateDraft(p.id, { min_bet_amount: e.target.value })}
                />
              </div>
              <div className="space-y-1.5 sm:col-span-2 lg:col-span-2">
                <Label htmlFor={`gap-${p.id}`}>{t("forceTriggerGap")}</Label>
                <Input
                  id={`gap-${p.id}`}
                  className="font-mono"
                  value={d.force_trigger_draw_gap}
                  onChange={(e) => updateDraft(p.id, { force_trigger_draw_gap: e.target.value })}
                />
              </div>
              <div className="space-y-2 sm:col-span-2 lg:col-span-3">
                <div>
                  <Label id={`combo-label-${p.id}`}>{t("comboTriggerPlays")}</Label>
                  <p className="text-xs text-muted-foreground">{t("comboTriggerPlaysHint")}</p>
                </div>
                {playOptions.length === 0 ? (
                  <p className="text-sm text-muted-foreground">{t("comboTriggerPlaysEmpty")}</p>
                ) : (
                  <div
                    role="group"
                    aria-labelledby={`combo-label-${p.id}`}
                    className="flex flex-wrap gap-2 rounded-md border border-border/60 p-2.5"
                  >
                    {playOptions.map((option) => {
                      const checked = d.combo_trigger_play_codes.includes(option.code);
                      return (
                        <label
                          key={option.code}
                          className="inline-flex cursor-pointer items-center gap-2 rounded-md border border-border/60 px-2.5 py-1.5 text-sm has-disabled:cursor-not-allowed has-disabled:opacity-60"
                        >
                          <Checkbox
                            checked={checked}
                            disabled={!canManageJackpot}
                            aria-label={option.label}
                            onCheckedChange={(value) => toggleComboPlay(p.id, option.code, value === true)}
                          />
                          <span>{option.label}</span>
                          <span className="font-mono text-xs text-muted-foreground">{option.code}</span>
                        </label>
                      );
                    })}
                    {d.combo_trigger_play_codes
                      .filter((code) => !playOptions.some((option) => option.code === code))
                      .map((code) => (
                        <label
                          key={`orphan-${code}`}
                          className="inline-flex cursor-pointer items-center gap-2 rounded-md border border-dashed border-amber-500/50 bg-amber-500/5 px-2.5 py-1.5 text-sm"
                        >
                          <Checkbox
                            checked
                            disabled={!canManageJackpot}
                            aria-label={code}
                            onCheckedChange={() => toggleComboPlay(p.id, code, false)}
                          />
                          <span className="font-mono text-xs">{code}</span>
                          <span className="text-xs text-amber-700 dark:text-amber-400">
                            {t("comboTriggerPlaysUnknown")}
                          </span>
                        </label>
                      ))}
                  </div>
                )}
              </div>
            </fieldset>

            {canManageJackpot ? (
              <div className="mt-4 border-t border-border/60 pt-3">
                <button
                  type="button"
                  className="text-sm font-medium text-foreground hover:underline"
                  onClick={() => toggleAdjustment(p.id, !adjustmentOpen)}
                >
                  {t("balanceAdjustmentTitle")}
                </button>
                {adjustmentOpen ? (
                  <div className="mt-3 grid gap-3 sm:grid-cols-2">
                    <div className="space-y-1.5">
                      <Label>{t("adjustmentDirection")}</Label>
                      <Select
                        value={adj.direction}
                        onValueChange={(value: "increase" | "decrease" | null) => {
                          if (value === null) return;
                          updateAdjustmentDraft(p.id, { direction: value });
                        }}
                      >
                        <SelectTrigger className="w-full min-w-0">
                          <SelectValue>
                            {(value) =>
                              value === "increase"
                                ? t("adjustmentIncrease")
                                : value === "decrease"
                                  ? t("adjustmentDecrease")
                                  : t("adjustmentIncrease")
                            }
                          </SelectValue>
                        </SelectTrigger>
                        <SelectContent>
                          <SelectItem value="increase">{t("adjustmentIncrease")}</SelectItem>
                          <SelectItem value="decrease">{t("adjustmentDecrease")}</SelectItem>
                        </SelectContent>
                      </Select>
                    </div>
                    <div className="space-y-1.5">
                      <Label htmlFor={`adj-amt-${p.id}`}>{t("adjustmentAmount")}</Label>
                      <Input
                        id={`adj-amt-${p.id}`}
                        className="font-mono"
                        value={adj.amount}
                        onChange={(e) => updateAdjustmentDraft(p.id, { amount: e.target.value })}
                      />
                    </div>
                    <div className="space-y-1.5 sm:col-span-2">
                      <Label htmlFor={`adj-reason-${p.id}`}>{t("adjustmentReason")}</Label>
                      <Textarea
                        id={`adj-reason-${p.id}`}
                        rows={2}
                        value={adj.reason}
                        onChange={(e) => updateAdjustmentDraft(p.id, { reason: e.target.value })}
                      />
                    </div>
                    <div className="flex justify-end sm:col-span-2">
                      <Button
                        type="button"
                        variant="secondary"
                        size="sm"
                        disabled={adjustingId === p.id}
                        onClick={() =>
                          requestConfirm({
                            title: t("confirmAdjustmentTitle"),
                            description: t("confirmAdjustmentDescription"),
                            confirmLabel: t("confirm.confirmSave", { ns: "common" }),
                            onConfirm: () => submitAdjustment(p),
                          })
                        }
                      >
                        {adjustingId === p.id ? t("processing") : t("submitAdjustment")}
                      </Button>
                    </div>
                    {ledger.length > 0 ? (
                      <ul className="space-y-1.5 sm:col-span-2">
                        {ledger.map((row) => (
                          <li
                            key={row.id}
                            className="flex items-center justify-between gap-2 rounded-md border border-border/60 px-2.5 py-1.5 text-xs"
                          >
                            <span className="truncate text-muted-foreground">{row.reason}</span>
                            <span className="shrink-0 font-mono font-medium">
                              {row.amount_delta > 0 ? "+" : ""}
                              {formatAdminMinorDecimal(row.amount_delta, p.currency_code)}
                            </span>
                          </li>
                        ))}
                      </ul>
                    ) : null}
                  </div>
                ) : null}
              </div>
            ) : null}

            {canManualBurst ? (
              <div className="mt-4 flex flex-col gap-2 border-t border-border/60 pt-3 sm:flex-row sm:items-end">
                <div className="min-w-0 flex-1 space-y-1.5 sm:max-w-xs">
                  <Label htmlFor={`burst-draw-${p.id}`}>{t("manualBurstDrawId")}</Label>
                  <Input
                    id={`burst-draw-${p.id}`}
                    className="font-mono"
                    value={d.manual_burst_draw_id}
                    onChange={(e) => updateDraft(p.id, { manual_burst_draw_id: e.target.value })}
                  />
                </div>
                <Button
                  type="button"
                  variant="destructive"
                  size="sm"
                  disabled={burstingId === p.id}
                  onClick={() => setConfirmBurstPoolId(p.id)}
                >
                  {burstingId === p.id ? t("processing") : t("manualBurst")}
                </Button>
              </div>
            ) : null}
          </AdminPageCard>
        );
      })}
    </div>
  );

  const confirmPool = confirmBurstPoolId !== null ? items.find((p) => p.id === confirmBurstPoolId) : null;
  const confirmDraft = confirmPool ? drafts[confirmPool.id] : null;

  const confirmDialog = (
    <Dialog open={confirmBurstPoolId !== null} onOpenChange={(open) => !open && setConfirmBurstPoolId(null)}>
      <DialogContent>
        <DialogHeader>
          <DialogTitle>{t("manualBurstConfirmTitle")}</DialogTitle>
          <DialogDescription>
            {t("manualBurstConfirmDescription", {
              drawId: confirmDraft?.manual_burst_draw_id ?? "—",
            })}
          </DialogDescription>
        </DialogHeader>
        <DialogFooter>
          <Button type="button" variant="outline" onClick={() => setConfirmBurstPoolId(null)}>
            {t("cancel")}
          </Button>
          <Button
            type="button"
            variant="destructive"
            disabled={confirmPool === undefined || burstingId !== null}
            onClick={() => confirmPool && void manualBurst(confirmPool)}
          >
            {t("manualBurstConfirm")}
          </Button>
        </DialogFooter>
      </DialogContent>
    </Dialog>
  );

  if (embedded) {
    return (
      <>
        {poolList}
        {confirmDialog}
        <ConfirmActionDialog />
      </>
    );
  }

  return (
    <ModuleScaffold>
      <Card>
        <CardHeader>
          <CardTitle className="text-base">{t("configTitle")}</CardTitle>
        </CardHeader>
        <CardContent>{poolList}</CardContent>
      </Card>
      {confirmDialog}
      <ConfirmActionDialog />
    </ModuleScaffold>
  );
}