"use client";

import { useCallback, useEffect, useMemo, useState } from "react";
import { useTranslation } from "react-i18next";
import { toast } from "sonner";

import {
  getAdminSettings,
  updateAdminSetting,
} from "@/api/admin-settings";
import { AdminPageCard } from "@/components/admin/admin-page-card";
import { useConfirmAction } from "@/hooks/use-confirm-action";
import { WalletConfigDocScreen } from "@/modules/config/doc/wallet-config-doc-screen";
import { Button } from "@/components/ui/button";
import { Input } from "@/components/ui/input";
import { Label } from "@/components/ui/label";
import { Switch } from "@/components/ui/switch";
import { Textarea } from "@/components/ui/textarea";
import { Tabs, TabsContent, TabsList, TabsTrigger } from "@/components/ui/tabs";
import { LotteryApiBizError } from "@/types/api/errors";

const DRAW_GROUP = "draw";
const SETTLEMENT_GROUP = "settlement";

const DRAW_KEYS = {
  DEFAULT_CURRENCY: "currency.default_code",
  DRAW_INTERVAL_MINUTES: "draw.interval_minutes",
  DRAW_BETTING_WINDOW_SECONDS: "draw.betting_window_seconds",
  DRAW_CLOSE_BEFORE_DRAW_SECONDS: "draw.close_before_draw_seconds",
  DRAW_BUFFER_DRAWS_AHEAD: "draw.buffer_draws_ahead",
  REQUIRE_MANUAL_REVIEW: "draw.require_manual_review",
  COOLDOWN_MINUTES: "draw.cooldown_minutes",
  CURRENCY_DISPLAY_DECIMALS: "currency.display_decimals",
  CURRENCY_DECIMAL_SEPARATOR: "currency.decimal_separator",
  CURRENCY_THOUSANDS_SEPARATOR: "currency.thousands_separator",
  AUTO_SETTLEMENT: "settlement.auto_run_on_tick",
  AUTO_APPROVE: "settlement.auto_approve_on_tick",
  AUTO_PAYOUT: "settlement.auto_payout_on_tick",
  APPLY_REBATE_TO_PAYOUT: "settlement.apply_rebate_to_payout",
} as const;

const FRONTEND_GROUP = "frontend";
const FRONTEND_KEYS = {
  PLAY_RULES_HTML: "frontend.play_rules_html",
  PLAY_RULES_HTML_ZH: "frontend.play_rules_html_zh",
  PLAY_RULES_HTML_EN: "frontend.play_rules_html_en",
  PLAY_RULES_HTML_NE: "frontend.play_rules_html_ne",
} as const;

interface RuntimeDraft {
  defaultCurrency: string;
  drawIntervalMinutes: string;
  drawBettingWindowSeconds: string;
  drawCloseBeforeDrawSeconds: string;
  drawBufferDrawsAhead: string;
  requireManualReview: boolean;
  cooldownMinutes: string;
  currencyDisplayDecimals: string;
  currencyDecimalSeparator: string;
  currencyThousandsSeparator: string;
  autoSettlement: boolean;
  autoApprove: boolean;
  autoPayout: boolean;
  applyRebateToPayout: boolean;
  playRulesHtmlZh: string;
  playRulesHtmlEn: string;
  playRulesHtmlNe: string;
}

const RUNTIME_DRAFT_KEYS = [
  "defaultCurrency",
  "drawIntervalMinutes",
  "drawBettingWindowSeconds",
  "drawCloseBeforeDrawSeconds",
  "drawBufferDrawsAhead",
  "requireManualReview",
  "cooldownMinutes",
  "currencyDisplayDecimals",
  "currencyDecimalSeparator",
  "currencyThousandsSeparator",
  "autoSettlement",
  "autoApprove",
  "autoPayout",
  "applyRebateToPayout",
] as const satisfies readonly (keyof RuntimeDraft)[];

const FRONTEND_DRAFT_KEYS = [
  "playRulesHtmlZh",
  "playRulesHtmlEn",
  "playRulesHtmlNe",
] as const satisfies readonly (keyof RuntimeDraft)[];

function isSectionDirty<const K extends keyof RuntimeDraft>(
  draft: RuntimeDraft,
  saved: RuntimeDraft,
  keys: readonly K[],
): boolean {
  return keys.some((key) => draft[key] !== saved[key]);
}

function applyDraftFields<const K extends keyof RuntimeDraft>(
  base: RuntimeDraft,
  source: RuntimeDraft,
  keys: readonly K[],
): RuntimeDraft {
  const next = { ...base };
  for (const key of keys) {
    next[key] = source[key];
  }
  return next;
}

function SaveActions({
  dirty,
  loading,
  saving,
  onSave,
  onDiscard,
  saveLabel,
  savingLabel,
  discardLabel,
}: {
  dirty: boolean;
  loading: boolean;
  saving: boolean;
  onSave: () => void;
  onDiscard: () => void;
  saveLabel: string;
  savingLabel: string;
  discardLabel: string;
}) {
  return (
    <div className="flex flex-wrap items-center gap-3 pt-2">
      <Button type="button" onClick={onSave} disabled={!dirty || loading || saving}>
        {saving ? savingLabel : saveLabel}
      </Button>
      {dirty ? (
        <Button type="button" variant="outline" onClick={onDiscard}>
          {discardLabel}
        </Button>
      ) : null}
    </div>
  );
}

export function SystemSettingsScreen() {
  const { t } = useTranslation(["common", "config", "adminUsers"]);
  const { request: requestConfirm, ConfirmDialog } = useConfirmAction();
  const [draft, setDraft] = useState<RuntimeDraft>({
    defaultCurrency: "NPR",
    drawIntervalMinutes: "5",
    drawBettingWindowSeconds: "270",
    drawCloseBeforeDrawSeconds: "30",
    drawBufferDrawsAhead: "8",
    requireManualReview: false,
    cooldownMinutes: "15",
    currencyDisplayDecimals: "2",
    currencyDecimalSeparator: ".",
    currencyThousandsSeparator: ",",
    autoSettlement: true,
    autoApprove: true,
    autoPayout: true,
    applyRebateToPayout: false,
    playRulesHtmlZh: "",
    playRulesHtmlEn: "",
    playRulesHtmlNe: "",
  });
  const [saved, setSaved] = useState<RuntimeDraft>({
    defaultCurrency: "NPR",
    drawIntervalMinutes: "5",
    drawBettingWindowSeconds: "270",
    drawCloseBeforeDrawSeconds: "30",
    drawBufferDrawsAhead: "8",
    requireManualReview: false,
    cooldownMinutes: "15",
    currencyDisplayDecimals: "2",
    currencyDecimalSeparator: ".",
    currencyThousandsSeparator: ",",
    autoSettlement: true,
    autoApprove: true,
    autoPayout: true,
    applyRebateToPayout: false,
    playRulesHtmlZh: "",
    playRulesHtmlEn: "",
    playRulesHtmlNe: "",
  });
  const [loading, setLoading] = useState(true);
  const [savingRuntime, setSavingRuntime] = useState(false);
  const [savingFrontend, setSavingFrontend] = useState(false);

  const runtimeDirty = useMemo(
    () => isSectionDirty(draft, saved, RUNTIME_DRAFT_KEYS),
    [draft, saved],
  );
  const frontendDirty = useMemo(
    () => isSectionDirty(draft, saved, FRONTEND_DRAFT_KEYS),
    [draft, saved],
  );
  const anyDirty = runtimeDirty || frontendDirty;
  const saving = savingRuntime || savingFrontend;

  const load = useCallback(async () => {
    setLoading(true);
    try {
      const [drawRes, settlementRes, frontendRes] = await Promise.all([
        getAdminSettings(DRAW_GROUP),
        getAdminSettings(SETTLEMENT_GROUP),
        getAdminSettings(FRONTEND_GROUP),
      ]);

      const kv: Record<string, unknown> = {};
      for (const item of [...drawRes.items, ...settlementRes.items, ...frontendRes.items]) {
        kv[item.key] = item.value;
      }

      const legacyHtml = String(kv[FRONTEND_KEYS.PLAY_RULES_HTML] ?? "");
      const nextDraft: RuntimeDraft = {
        defaultCurrency: String(kv[DRAW_KEYS.DEFAULT_CURRENCY] ?? "NPR"),
        drawIntervalMinutes: String(kv[DRAW_KEYS.DRAW_INTERVAL_MINUTES] ?? 5),
        drawBettingWindowSeconds: String(kv[DRAW_KEYS.DRAW_BETTING_WINDOW_SECONDS] ?? 270),
        drawCloseBeforeDrawSeconds: String(kv[DRAW_KEYS.DRAW_CLOSE_BEFORE_DRAW_SECONDS] ?? 30),
        drawBufferDrawsAhead: String(kv[DRAW_KEYS.DRAW_BUFFER_DRAWS_AHEAD] ?? 8),
        requireManualReview: Boolean(kv[DRAW_KEYS.REQUIRE_MANUAL_REVIEW] ?? false),
        cooldownMinutes: String(kv[DRAW_KEYS.COOLDOWN_MINUTES] ?? 15),
        currencyDisplayDecimals: String(kv[DRAW_KEYS.CURRENCY_DISPLAY_DECIMALS] ?? 2),
        currencyDecimalSeparator: String(kv[DRAW_KEYS.CURRENCY_DECIMAL_SEPARATOR] ?? "."),
        currencyThousandsSeparator: String(kv[DRAW_KEYS.CURRENCY_THOUSANDS_SEPARATOR] ?? ","),
        autoSettlement: Boolean(kv[DRAW_KEYS.AUTO_SETTLEMENT] ?? true),
        autoApprove: Boolean(kv[DRAW_KEYS.AUTO_APPROVE] ?? true),
        autoPayout: Boolean(kv[DRAW_KEYS.AUTO_PAYOUT] ?? true),
        applyRebateToPayout: Boolean(kv[DRAW_KEYS.APPLY_REBATE_TO_PAYOUT] ?? false),
        playRulesHtmlZh: String(kv[FRONTEND_KEYS.PLAY_RULES_HTML_ZH] ?? legacyHtml),
        playRulesHtmlEn: String(kv[FRONTEND_KEYS.PLAY_RULES_HTML_EN] ?? ""),
        playRulesHtmlNe: String(kv[FRONTEND_KEYS.PLAY_RULES_HTML_NE] ?? ""),
      };
      setDraft(nextDraft);
      setSaved(nextDraft);
    } catch {
      toast.error(t("system.loadFailed", { ns: "config" }));
    } finally {
      setLoading(false);
    }
  }, [t]);

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

  const updateDraft = <K extends keyof RuntimeDraft>(field: K, value: RuntimeDraft[K]) => {
    setDraft((prev) => ({ ...prev, [field]: value }));
  };

  const discardSection = <const K extends keyof RuntimeDraft>(keys: readonly K[]) => {
    setDraft((prev) => applyDraftFields(prev, saved, keys));
  };

  const handleSaveRuntime = async () => {
    setSavingRuntime(true);
    try {
      await updateAdminSetting(
        DRAW_KEYS.DEFAULT_CURRENCY,
        draft.defaultCurrency.trim().toUpperCase() || "NPR",
      );
      await updateAdminSetting(
        DRAW_KEYS.DRAW_INTERVAL_MINUTES,
        Math.max(1, Number.parseInt(draft.drawIntervalMinutes || "5", 10) || 5),
      );
      await updateAdminSetting(
        DRAW_KEYS.DRAW_BETTING_WINDOW_SECONDS,
        Math.max(10, Number.parseInt(draft.drawBettingWindowSeconds || "270", 10) || 270),
      );
      await updateAdminSetting(
        DRAW_KEYS.DRAW_CLOSE_BEFORE_DRAW_SECONDS,
        Math.max(5, Number.parseInt(draft.drawCloseBeforeDrawSeconds || "30", 10) || 30),
      );
      await updateAdminSetting(
        DRAW_KEYS.DRAW_BUFFER_DRAWS_AHEAD,
        Math.max(1, Number.parseInt(draft.drawBufferDrawsAhead || "8", 10) || 8),
      );
      await updateAdminSetting(DRAW_KEYS.REQUIRE_MANUAL_REVIEW, draft.requireManualReview);
      await updateAdminSetting(
        DRAW_KEYS.COOLDOWN_MINUTES,
        Math.max(0, Number.parseInt(draft.cooldownMinutes || "0", 10) || 0),
      );
      await updateAdminSetting(
        DRAW_KEYS.CURRENCY_DISPLAY_DECIMALS,
        Math.max(0, Math.min(12, Number.parseInt(draft.currencyDisplayDecimals || "2", 10) || 2)),
      );
      await updateAdminSetting(
        DRAW_KEYS.CURRENCY_DECIMAL_SEPARATOR,
        (draft.currencyDecimalSeparator || ".").slice(0, 1),
      );
      await updateAdminSetting(
        DRAW_KEYS.CURRENCY_THOUSANDS_SEPARATOR,
        (draft.currencyThousandsSeparator || ",").slice(0, 1),
      );
      await updateAdminSetting(DRAW_KEYS.AUTO_SETTLEMENT, draft.autoSettlement);
      await updateAdminSetting(DRAW_KEYS.AUTO_APPROVE, draft.autoApprove);
      await updateAdminSetting(DRAW_KEYS.AUTO_PAYOUT, draft.autoPayout);
      await updateAdminSetting(DRAW_KEYS.APPLY_REBATE_TO_PAYOUT, draft.applyRebateToPayout);
      toast.success(t("system.saveRuntimeSuccess", { ns: "config" }));
      setSaved((prev) => applyDraftFields(prev, draft, RUNTIME_DRAFT_KEYS));
    } catch (error) {
      toast.error(
        error instanceof LotteryApiBizError ? error.message : t("system.saveFailed", { ns: "config" }),
      );
    } finally {
      setSavingRuntime(false);
    }
  };

  const handleSaveFrontend = async () => {
    setSavingFrontend(true);
    try {
      await updateAdminSetting(FRONTEND_KEYS.PLAY_RULES_HTML_ZH, draft.playRulesHtmlZh);
      await updateAdminSetting(FRONTEND_KEYS.PLAY_RULES_HTML_EN, draft.playRulesHtmlEn);
      await updateAdminSetting(FRONTEND_KEYS.PLAY_RULES_HTML_NE, draft.playRulesHtmlNe);
      await updateAdminSetting(FRONTEND_KEYS.PLAY_RULES_HTML, draft.playRulesHtmlZh);
      toast.success(t("system.saveFrontendSuccess", { ns: "config" }));
      setSaved((prev) => applyDraftFields(prev, draft, FRONTEND_DRAFT_KEYS));
    } catch (error) {
      toast.error(
        error instanceof LotteryApiBizError ? error.message : t("system.saveFailed", { ns: "config" }),
      );
    } finally {
      setSavingFrontend(false);
    }
  };

  const saveLabel = t("actions.save", { ns: "adminUsers" });
  const savingLabel = t("saving", { ns: "adminUsers" });
  const discardLabel = t("system.discard", { ns: "config" });

  return (
    <div className="flex w-full max-w-none flex-col gap-6">
      {anyDirty ? (
        <div className="sticky top-0 z-20 -mx-1 rounded-lg border border-amber-500/40 bg-amber-500/10 px-4 py-3 shadow-sm backdrop-blur-sm">
          <p className="text-sm font-medium text-amber-950 dark:text-amber-100">
            {t("system.unsavedChanges", { ns: "config" })}
            {runtimeDirty && frontendDirty
              ? ` · ${t("system.title", { ns: "config" })} / ${t("system.frontendConfig", { ns: "config" })}`
              : runtimeDirty
                ? ` · ${t("system.title", { ns: "config" })}`
                : ` · ${t("system.frontendConfig", { ns: "config" })}`}
          </p>
        </div>
      ) : null}

      <AdminPageCard
        title={t("system.title", { ns: "config" })}
        description={t("system.description", { ns: "config" })}
      >
        <div className="space-y-5">
          <div className="flex flex-wrap items-center justify-between gap-3">
            <Label className="text-sm font-medium">{t("system.fields.manualReview", { ns: "config" })}</Label>
            <Switch
              checked={draft.requireManualReview}
              disabled={loading || saving}
              aria-label={t("system.fields.manualReview", { ns: "config" })}
              onCheckedChange={(value) => updateDraft("requireManualReview", value)}
            />
          </div>

          <div className="h-px bg-border/60" />

          <div className="grid grid-cols-1 gap-4 md:grid-cols-2">
            <div className="grid gap-2">
              <Label htmlFor="default-currency" className="text-sm font-medium">
                {t("system.fields.defaultCurrency", { ns: "config" })}
              </Label>
              <Input
                id="default-currency"
                value={draft.defaultCurrency}
                onChange={(e) => updateDraft("defaultCurrency", e.target.value.toUpperCase())}
                disabled={loading || saving}
                maxLength={16}
              />
            </div>
            <div className="grid gap-2">
              <Label htmlFor="draw-interval-minutes" className="text-sm font-medium">
                {t("system.fields.drawIntervalMinutes", { ns: "config" })}
              </Label>
              <Input
                id="draw-interval-minutes"
                type="number"
                min="1"
                max="1440"
                step="1"
                value={draft.drawIntervalMinutes}
                onChange={(e) => updateDraft("drawIntervalMinutes", e.target.value)}
                disabled={loading || saving}
              />
            </div>
            <div className="grid gap-2">
              <Label htmlFor="draw-betting-window-seconds" className="text-sm font-medium">
                {t("system.fields.drawBettingWindowSeconds", { ns: "config" })}
              </Label>
              <Input
                id="draw-betting-window-seconds"
                type="number"
                min="10"
                step="1"
                value={draft.drawBettingWindowSeconds}
                onChange={(e) => updateDraft("drawBettingWindowSeconds", e.target.value)}
                disabled={loading || saving}
              />
            </div>
            <div className="grid gap-2">
              <Label htmlFor="draw-close-before-seconds" className="text-sm font-medium">
                {t("system.fields.drawCloseBeforeDrawSeconds", { ns: "config" })}
              </Label>
              <Input
                id="draw-close-before-seconds"
                type="number"
                min="5"
                step="1"
                value={draft.drawCloseBeforeDrawSeconds}
                onChange={(e) => updateDraft("drawCloseBeforeDrawSeconds", e.target.value)}
                disabled={loading || saving}
              />
            </div>
            <div className="grid gap-2">
              <Label htmlFor="draw-buffer-ahead" className="text-sm font-medium">
                {t("system.fields.drawBufferDrawsAhead", { ns: "config" })}
              </Label>
              <Input
                id="draw-buffer-ahead"
                type="number"
                min="1"
                step="1"
                value={draft.drawBufferDrawsAhead}
                onChange={(e) => updateDraft("drawBufferDrawsAhead", e.target.value)}
                disabled={loading || saving}
              />
            </div>
            <div className="grid gap-2">
              <Label htmlFor="currency-display-decimals" className="text-sm font-medium">
                {t("system.fields.currencyDisplayDecimals", { ns: "config" })}
              </Label>
              <Input
                id="currency-display-decimals"
                type="number"
                min="0"
                max="12"
                step="1"
                value={draft.currencyDisplayDecimals}
                onChange={(e) => updateDraft("currencyDisplayDecimals", e.target.value)}
                disabled={loading || saving}
              />
            </div>
            <div className="grid gap-2">
              <Label htmlFor="currency-decimal-separator" className="text-sm font-medium">
                {t("system.fields.currencyDecimalSeparator", { ns: "config" })}
              </Label>
              <Input
                id="currency-decimal-separator"
                value={draft.currencyDecimalSeparator}
                onChange={(e) => updateDraft("currencyDecimalSeparator", e.target.value)}
                disabled={loading || saving}
                maxLength={1}
              />
            </div>
            <div className="grid gap-2">
              <Label htmlFor="currency-thousands-separator" className="text-sm font-medium">
                {t("system.fields.currencyThousandsSeparator", { ns: "config" })}
              </Label>
              <Input
                id="currency-thousands-separator"
                value={draft.currencyThousandsSeparator}
                onChange={(e) => updateDraft("currencyThousandsSeparator", e.target.value)}
                disabled={loading || saving}
                maxLength={1}
              />
            </div>
          </div>

          <div className="h-px bg-border/60" />

          <div className="flex flex-wrap items-center justify-between gap-3">
            <Label className="text-sm font-medium">{t("system.fields.autoSettlement", { ns: "config" })}</Label>
            <Switch
              checked={draft.autoSettlement}
              disabled={loading || saving}
              aria-label={t("system.fields.autoSettlement", { ns: "config" })}
              onCheckedChange={(value) => updateDraft("autoSettlement", value)}
            />
          </div>

          <div className="h-px bg-border/60" />

          <div className="flex flex-wrap items-center justify-between gap-3">
            <Label className="text-sm font-medium">{t("system.fields.autoApprove", { ns: "config" })}</Label>
            <Switch
              checked={draft.autoApprove}
              disabled={loading || saving}
              aria-label={t("system.fields.autoApprove", { ns: "config" })}
              onCheckedChange={(value) => updateDraft("autoApprove", value)}
            />
          </div>

          <div className="h-px bg-border/60" />

          <div className="flex flex-wrap items-center justify-between gap-3">
            <Label className="text-sm font-medium">{t("system.fields.autoPayout", { ns: "config" })}</Label>
            <Switch
              checked={draft.autoPayout}
              disabled={loading || saving}
              aria-label={t("system.fields.autoPayout", { ns: "config" })}
              onCheckedChange={(value) => updateDraft("autoPayout", value)}
            />
          </div>

          <div className="h-px bg-border/60" />

          <div className="flex flex-wrap items-center justify-between gap-3">
            <div className="min-w-0 space-y-1 pr-4">
              <Label className="text-sm font-medium">{t("system.fields.applyRebateToPayout", { ns: "config" })}</Label>
              <p className="text-xs text-muted-foreground">{t("system.hints.applyRebateToPayout", { ns: "config" })}</p>
            </div>
            <Switch
              checked={draft.applyRebateToPayout}
              disabled={loading || saving}
              aria-label={t("system.fields.applyRebateToPayout", { ns: "config" })}
              onCheckedChange={(value) => updateDraft("applyRebateToPayout", value)}
            />
          </div>

          <div className="h-px bg-border/60" />

          <div className="grid max-w-xs gap-2">
            <Label htmlFor="cooldown-minutes" className="text-sm font-medium">
              {t("system.fields.cooldownMinutes", { ns: "config" })}
            </Label>
            <Input
              id="cooldown-minutes"
              type="number"
              min="0"
              step="1"
              value={draft.cooldownMinutes}
              onChange={(e) => updateDraft("cooldownMinutes", e.target.value)}
              disabled={loading || saving}
            />
          </div>

          <SaveActions
            dirty={runtimeDirty}
            loading={loading}
            saving={savingRuntime}
            onSave={() =>
              requestConfirm({
                title: t("system.confirmSaveRuntimeTitle", { ns: "config" }),
                description: t("system.confirmSaveRuntimeDescription", { ns: "config" }),
                confirmLabel: t("confirm.confirmSave", { ns: "common" }),
                onConfirm: () => handleSaveRuntime(),
              })
            }
            onDiscard={() => discardSection(RUNTIME_DRAFT_KEYS)}
            saveLabel={saveLabel}
            savingLabel={savingLabel}
            discardLabel={discardLabel}
          />
        </div>
      </AdminPageCard>

      <AdminPageCard
        title={t("wallet.title", { ns: "config" })}
        description={t("wallet.description", { ns: "config" })}
      >
        <WalletConfigDocScreen embedded />
      </AdminPageCard>

      <AdminPageCard title={t("system.frontendConfig", { ns: "config" })}>
        <div className="grid gap-2">
          <Label className="text-sm font-medium">
            {t("system.fields.playRulesHtml", { ns: "config" })}
          </Label>
          <p className="text-xs text-muted-foreground">
            {t("system.fields.playRulesHtmlDesc", { ns: "config" })}
          </p>
          <Tabs defaultValue="zh" className="w-full">
            <TabsList className="w-full max-w-md">
              <TabsTrigger value="zh">{t("play.locales.zh", { ns: "config" })}</TabsTrigger>
              <TabsTrigger value="en">{t("play.locales.en", { ns: "config" })}</TabsTrigger>
              <TabsTrigger value="ne">{t("play.locales.ne", { ns: "config" })}</TabsTrigger>
            </TabsList>
            <TabsContent value="zh" className="mt-3">
              <Textarea
                id="play-rules-html-zh"
                value={draft.playRulesHtmlZh}
                onChange={(e) => updateDraft("playRulesHtmlZh", e.target.value)}
                disabled={loading || saving}
                className="min-h-[200px] font-mono text-xs"
                placeholder="<div>...</div>"
              />
            </TabsContent>
            <TabsContent value="en" className="mt-3">
              <Textarea
                id="play-rules-html-en"
                value={draft.playRulesHtmlEn}
                onChange={(e) => updateDraft("playRulesHtmlEn", e.target.value)}
                disabled={loading || saving}
                className="min-h-[200px] font-mono text-xs"
                placeholder="<div>...</div>"
              />
            </TabsContent>
            <TabsContent value="ne" className="mt-3">
              <Textarea
                id="play-rules-html-ne"
                value={draft.playRulesHtmlNe}
                onChange={(e) => updateDraft("playRulesHtmlNe", e.target.value)}
                disabled={loading || saving}
                className="min-h-[200px] font-mono text-xs"
                placeholder="<div>...</div>"
              />
            </TabsContent>
          </Tabs>

          <SaveActions
            dirty={frontendDirty}
            loading={loading}
            saving={savingFrontend}
            onSave={() =>
              requestConfirm({
                title: t("system.confirmSaveFrontendTitle", { ns: "config" }),
                description: t("system.confirmSaveFrontendDescription", { ns: "config" }),
                confirmLabel: t("confirm.confirmSave", { ns: "common" }),
                onConfirm: () => handleSaveFrontend(),
              })
            }
            onDiscard={() => discardSection(FRONTEND_DRAFT_KEYS)}
            saveLabel={saveLabel}
            savingLabel={savingLabel}
            discardLabel={discardLabel}
          />
        </div>
      </AdminPageCard>

      <ConfirmDialog />
    </div>
  );
}
