"use client";

import { Copy, Download, Link2, Pencil, ShieldAlert, Trash2 } from "lucide-react";
import { useCallback, useRef, useState } from "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 {
  deleteAdminIntegrationSite,
  getAdminIntegrationSite,
  getAdminIntegrationSiteExport,
  getAdminIntegrationSites,
  getAdminIntegrationSiteSecrets,
  postAdminIntegrationSite,
  postAdminIntegrationSiteConnectivityTest,
  postAdminIntegrationSiteRotateSecrets,
  putAdminIntegrationSite,
} from "@/api/admin-integration-sites";
import { AdminPageCard } from "@/components/admin/admin-page-card";
import { AdminNoResourceState } from "@/components/admin/admin-no-resource-state";
import { AdminRowActionsMenu } from "@/components/admin/admin-row-actions-menu";
import { AdminStatusBadge } from "@/components/admin/admin-status-badge";
import { Button } from "@/components/ui/button";
import {
  Dialog,
  DialogContent,
  DialogDescription,
  DialogFooter,
  DialogHeader,
  DialogTitle,
} from "@/components/ui/dialog";
import { Input } from "@/components/ui/input";
import { Label } from "@/components/ui/label";
import {
  Table,
  TableBody,
  TableCell,
  TableHead,
  TableHeader,
  TableRow,
} from "@/components/ui/table";
import { Textarea } from "@/components/ui/textarea";
import { AdminLoadingState } from "@/components/admin/admin-loading-state";
import { adminHasAnyPermission } from "@/lib/admin-permissions";
import { getAdminPageBundle } from "@/lib/admin-permission-bundles";
import { useAdminProfile } from "@/stores/admin-session";
import { LotteryApiBizError } from "@/types/api/errors";
import type {
  AdminIntegrationSiteCreatePayload,
  AdminIntegrationSiteConnectivityResult,
  AdminIntegrationSiteUpdatePayload,
  AdminIntegrationSiteRow,
  AdminIntegrationSiteDetail,
  AdminIntegrationSiteSecrets,
  AdminIntegrationSiteWithSecrets,
} from "@/types/api/admin-integration-site";

function CopyIconButton({
  label,
  onClick,
  disabled,
  busy,
}: {
  label: string;
  onClick: () => void;
  disabled?: boolean;
  busy?: boolean;
}): React.ReactElement {
  return (
    <Button
      type="button"
      variant="ghost"
      size="icon"
      className="h-7 w-7 shrink-0"
      disabled={disabled || busy}
      aria-label={label}
      title={label}
      onClick={onClick}
    >
      <Copy className="h-3.5 w-3.5" />
    </Button>
  );
}

function MaskedValueWithCopy({
  configured,
  masked,
  copyLabel,
  canCopy,
  copying,
  onCopy,
}: {
  configured: boolean;
  masked: string | null;
  copyLabel: string;
  canCopy: boolean;
  copying: boolean;
  onCopy: () => void;
}): React.ReactElement {
  return (
    <div className="flex min-w-[7.5rem] max-w-[11rem] items-center gap-0.5">
      <span className="truncate font-mono text-xs text-muted-foreground">
        {configured ? (masked ?? "••••••••") : "—"}
      </span>
      {configured && canCopy ? (
        <CopyIconButton label={copyLabel} onClick={onCopy} busy={copying} />
      ) : null}
    </div>
  );
}

type FormState = {
  code: string;
  name: string;
  admin_username: string;
  admin_nickname: string;
  admin_password: string;
  admin_email: string;
  currency_code: string;
  status: number;
  wallet_api_url: string;
  wallet_debit_path: string;
  wallet_credit_path: string;
  wallet_balance_path: string;
  wallet_timeout_seconds: string;
  iframe_allowed_origins: string;
  lottery_h5_base_url: string;
  notes: string;
};

const EMPTY_FORM: FormState = {
  code: "",
  name: "",
  admin_username: "",
  admin_nickname: "",
  admin_password: "",
  admin_email: "",
  currency_code: "NPR",
  status: 1,
  wallet_api_url: "",
  wallet_debit_path: "/wallet/debit-for-lottery",
  wallet_credit_path: "/wallet/credit-from-lottery",
  wallet_balance_path: "/wallet/balance",
  wallet_timeout_seconds: "10",
  iframe_allowed_origins: "",
  lottery_h5_base_url: "",
  notes: "",
};

function originsToText(origins: string[] | undefined): string {
  return (origins ?? []).join("\n");
}

function textToOrigins(text: string): string[] {
  return text
    .split(/[\n,]+/)
    .map((s) => s.trim())
    .filter(Boolean);
}

function rowToForm(row: AdminIntegrationSiteDetail): FormState {
  return {
    code: row.code,
    name: row.name,
    admin_username: "",
    admin_nickname: "",
    admin_password: "",
    admin_email: "",
    currency_code: row.currency_code,
    status: row.status,
    wallet_api_url: row.wallet_api_url ?? "",
    wallet_debit_path: row.wallet_debit_path ?? "/wallet/debit-for-lottery",
    wallet_credit_path: row.wallet_credit_path ?? "/wallet/credit-from-lottery",
    wallet_balance_path: row.wallet_balance_path ?? "/wallet/balance",
    wallet_timeout_seconds: String(row.wallet_timeout_seconds ?? 10),
    iframe_allowed_origins: originsToText(row.iframe_allowed_origins as string[] | undefined),
    lottery_h5_base_url: row.lottery_h5_base_url ?? "",
    notes: row.notes ?? "",
  };
}

function formToPayload(form: FormState, includeCode: true): AdminIntegrationSiteCreatePayload;
function formToPayload(form: FormState, includeCode: false): AdminIntegrationSiteUpdatePayload;
function formToPayload(
  form: FormState,
  includeCode: boolean,
): AdminIntegrationSiteCreatePayload | AdminIntegrationSiteUpdatePayload {
  const base = {
    name: form.name.trim(),
    currency_code: form.currency_code.trim() || "NPR",
    status: form.status,
    wallet_api_url: form.wallet_api_url.trim() || null,
    wallet_debit_path: form.wallet_debit_path.trim(),
    wallet_credit_path: form.wallet_credit_path.trim(),
    wallet_balance_path: form.wallet_balance_path.trim(),
    wallet_timeout_seconds: Number.parseInt(form.wallet_timeout_seconds, 10) || 10,
    iframe_allowed_origins: textToOrigins(form.iframe_allowed_origins),
    lottery_h5_base_url: form.lottery_h5_base_url.trim() || null,
    notes: form.notes.trim() || null,
  };

  if (includeCode) {
    return {
      code: form.code.trim(),
      admin_account: {
        username: form.admin_username.trim(),
        nickname: form.admin_nickname.trim(),
        password: form.admin_password,
        email: form.admin_email.trim() || null,
      },
      ...base,
    };
  }

  return base;
}

type IntegrationSitesConsoleProps = {
  /** 为 true 时仅超管可新建站点（默认有 integration.site.manage 即可创建）。 */
  restrictCreateToSuperAdmin?: boolean;
};

export function IntegrationSitesConsole({
  restrictCreateToSuperAdmin = false,
}: IntegrationSitesConsoleProps = {}) {
  const { t } = useTranslation("config");
  const tRef = useTranslationRef("config");
  const profile = useAdminProfile();
  const canManage = adminHasAnyPermission(
    profile?.permissions,
    getAdminPageBundle("integration-sites", "manage"),
  );
  const canCreate =
    canManage &&
    (!restrictCreateToSuperAdmin || profile?.is_super_admin === true);

  const [items, setItems] = useState<AdminIntegrationSiteRow[]>([]);
  const [loading, setLoading] = useState(true);
  const [saving, setSaving] = useState(false);
  const [dialogOpen, setDialogOpen] = useState(false);
  const [mode, setMode] = useState<"create" | "edit">("create");
  const [editingId, setEditingId] = useState<number | null>(null);
  const [form, setForm] = useState<FormState>(EMPTY_FORM);
  const [rotateTarget, setRotateTarget] = useState<AdminIntegrationSiteRow | null>(null);
  const [deleteTarget, setDeleteTarget] = useState<AdminIntegrationSiteRow | null>(null);
  const [deleteBusy, setDeleteBusy] = useState(false);
  const [rotateBusy, setRotateBusy] = useState(false);
  const [secretsDialog, setSecretsDialog] = useState<{
    siteCode: string;
    secrets: AdminIntegrationSiteSecrets;
  } | null>(null);
  const [connectivityTarget, setConnectivityTarget] = useState<AdminIntegrationSiteRow | null>(
    null,
  );
  const [connectivityPlayerId, setConnectivityPlayerId] = useState("10001");
  const [connectivityCurrency, setConnectivityCurrency] = useState("NPR");
  const [connectivityBusy, setConnectivityBusy] = useState(false);
  const [connectivityResult, setConnectivityResult] =
    useState<AdminIntegrationSiteConnectivityResult | null>(null);
  const [exportBusyId, setExportBusyId] = useState<number | null>(null);
  const [secretCopyBusyKey, setSecretCopyBusyKey] = useState<string | null>(null);
  const secretsCacheRef = useRef(new Map<number, AdminIntegrationSiteSecrets>());

  const load = useCallback(async () => {
    setLoading(true);
    secretsCacheRef.current.clear();
    try {
      const data = await getAdminIntegrationSites();
      setItems(data.items);
    } catch (error) {
      toast.error(
        error instanceof LotteryApiBizError ? error.message : tRef.current("integrationSites.loadFailed"),
      );
    } finally {
      setLoading(false);
    }
  }, [tRef]);

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

  function openCreate(): void {
    setMode("create");
    setEditingId(null);
    setForm(EMPTY_FORM);
    setDialogOpen(true);
  }

  async function openEdit(row: AdminIntegrationSiteRow): Promise<void> {
    setMode("edit");
    setEditingId(row.id);
    setDialogOpen(true);
    try {
      const detail = await getAdminIntegrationSite(row.id);
      setForm(rowToForm(detail));
    } catch (error) {
      toast.error(
        error instanceof LotteryApiBizError ? error.message : t("integrationSites.loadFailed"),
      );
      setDialogOpen(false);
    }
  }

  function updateForm<K extends keyof FormState>(key: K, value: FormState[K]): void {
    setForm((prev) => ({ ...prev, [key]: value }));
  }

  function showSecretsOnce(result: AdminIntegrationSiteWithSecrets): void {
    if (result.secrets) {
      setSecretsDialog({ siteCode: result.code, secrets: result.secrets });
    }
  }

  async function handleSubmit(): Promise<void> {
    if (!canManage) return;

    if (form.name.trim() === "") {
      toast.error(t("integrationSites.form.required"));
      return;
    }

    if (mode === "create" && form.code.trim() === "") {
      toast.error(t("integrationSites.form.codeRequired"));
      return;
    }

    if (mode === "create" && form.admin_username.trim() === "") {
      toast.error(t("integrationSites.form.adminUsernameRequired"));
      return;
    }

    if (mode === "create" && form.admin_nickname.trim() === "") {
      toast.error(t("integrationSites.form.adminNicknameRequired"));
      return;
    }

    if (mode === "create" && form.admin_password.trim().length < 8) {
      toast.error(t("integrationSites.form.adminPasswordRequired"));
      return;
    }

    setSaving(true);
    try {
      if (mode === "create") {
        const created = await postAdminIntegrationSite(formToPayload(form, true));
        toast.success(t("integrationSites.createSuccess", { code: created.code }));
        if (created.admin_user?.username) {
          toast.success(
            t("integrationSites.adminAccountCreated", {
              username: created.admin_user.username,
              defaultValue: "已同时创建站点后台账号 {{username}}",
            }),
          );
        }
        showSecretsOnce(created);
      } else if (editingId !== null) {
        await putAdminIntegrationSite(editingId, formToPayload(form, false));
        toast.success(t("integrationSites.updateSuccess", { code: form.code }));
      }
      setDialogOpen(false);
      await load();
    } catch (error) {
      toast.error(
        error instanceof LotteryApiBizError ? error.message : t("integrationSites.saveFailed"),
      );
    } finally {
      setSaving(false);
    }
  }

  async function confirmRotate(): Promise<void> {
    if (!rotateTarget || !canManage) return;

    setRotateBusy(true);
    try {
      const result = await postAdminIntegrationSiteRotateSecrets(rotateTarget.id);
      toast.success(t("integrationSites.rotateSuccess", { code: rotateTarget.code }));
      setRotateTarget(null);
      secretsCacheRef.current.delete(rotateTarget.id);
      showSecretsOnce(result);
      await load();
    } catch (error) {
      toast.error(
        error instanceof LotteryApiBizError ? error.message : t("integrationSites.rotateFailed"),
      );
    } finally {
      setRotateBusy(false);
    }
  }

  async function confirmDelete(): Promise<void> {
    if (!deleteTarget || !canManage) return;

    setDeleteBusy(true);
    try {
      await deleteAdminIntegrationSite(deleteTarget.id);
      toast.success(t("integrationSites.deleteSuccess", { code: deleteTarget.code }));
      secretsCacheRef.current.delete(deleteTarget.id);
      setDeleteTarget(null);
      await load();
    } catch (error) {
      toast.error(
        error instanceof LotteryApiBizError ? error.message : t("integrationSites.deleteFailed"),
      );
    } finally {
      setDeleteBusy(false);
    }
  }

  function openConnectivity(row: AdminIntegrationSiteRow): void {
    setConnectivityTarget(row);
    setConnectivityPlayerId("10001");
    setConnectivityCurrency(row.currency_code || "NPR");
    setConnectivityResult(null);
  }

  async function runConnectivityTest(): Promise<void> {
    if (!connectivityTarget) return;

    setConnectivityBusy(true);
    setConnectivityResult(null);
    try {
      const result = await postAdminIntegrationSiteConnectivityTest(connectivityTarget.id, {
        site_player_id: connectivityPlayerId.trim(),
        currency_code: connectivityCurrency.trim() || undefined,
      });
      setConnectivityResult(result);
      if (result.probe.success) {
        toast.success(t("integrationSites.connectivitySuccess"));
      } else {
        toast.error(result.probe.message ?? t("integrationSites.connectivityFailed"));
      }
    } catch (error) {
      toast.error(
        error instanceof LotteryApiBizError
          ? error.message
          : t("integrationSites.connectivityFailed"),
      );
    } finally {
      setConnectivityBusy(false);
    }
  }

  async function exportParameterSheet(row: AdminIntegrationSiteRow): Promise<void> {
    setExportBusyId(row.id);
    try {
      const sheet = await getAdminIntegrationSiteExport(row.id);
      const blob = new Blob([JSON.stringify(sheet, null, 2)], {
        type: "application/json;charset=utf-8",
      });
      const url = URL.createObjectURL(blob);
      const anchor = document.createElement("a");
      anchor.href = url;
      anchor.download = `integration-${row.code}.json`;
      anchor.click();
      URL.revokeObjectURL(url);
      toast.success(t("integrationSites.exportSuccess", { code: row.code }));
    } catch (error) {
      toast.error(
        error instanceof LotteryApiBizError ? error.message : t("integrationSites.exportFailed"),
      );
    } finally {
      setExportBusyId(null);
    }
  }

  async function copyText(label: string, value: string): Promise<void> {
    try {
      await navigator.clipboard.writeText(value);
      toast.success(t("integrationSites.copied", { field: label }));
    } catch {
      toast.error(t("integrationSites.copyFailed"));
    }
  }

  async function resolveSiteSecrets(siteId: number): Promise<AdminIntegrationSiteSecrets> {
    const cached = secretsCacheRef.current.get(siteId);
    if (cached) {
      return cached;
    }
    const secrets = await getAdminIntegrationSiteSecrets(siteId);
    secretsCacheRef.current.set(siteId, secrets);
    return secrets;
  }

  async function copySiteSecret(
    row: AdminIntegrationSiteRow,
    field: "sso" | "wallet",
  ): Promise<void> {
    if (!canManage) {
      toast.error(t("integrationSites.secretCopyRequiresManage"));
      return;
    }

    const configured = field === "sso" ? row.has_sso_secret : row.has_wallet_api_key;
    if (!configured) {
      toast.error(t("integrationSites.secretNotConfigured"));
      return;
    }

    const busyKey = `${row.id}:${field}`;
    setSecretCopyBusyKey(busyKey);
    try {
      const secrets = await resolveSiteSecrets(row.id);
      const value = field === "sso" ? secrets.sso_jwt_secret : secrets.wallet_api_key;
      if (!value) {
        toast.error(t("integrationSites.secretNotConfigured"));
        return;
      }
      await copyText(
        field === "sso"
          ? t("integrationSites.fields.ssoSecret")
          : t("integrationSites.fields.walletApiKey"),
        value,
      );
    } catch (error) {
      toast.error(
        error instanceof LotteryApiBizError ? error.message : t("integrationSites.copyFailed"),
      );
    } finally {
      setSecretCopyBusyKey(null);
    }
  }

  return (
    <>
      <AdminPageCard
        title={t("integrationSites.title")}
        description={t("integrationSites.description")}
        actions={
          canCreate ? (
            <Button type="button" onClick={openCreate}>
              {t("integrationSites.create")}
            </Button>
          ) : null
        }
      >
        {loading ? (
          <AdminLoadingState minHeight="8rem" label={t("integrationSites.loading")} />
        ) : items.length === 0 ? (
          <AdminNoResourceState message={t("integrationSites.empty")}>
            {canCreate ? (
              <Button type="button" size="sm" onClick={openCreate}>
                {t("integrationSites.create")}
              </Button>
            ) : null}
          </AdminNoResourceState>
        ) : (
          <div className="overflow-x-auto">
          <Table>
            <TableHeader>
              <TableRow>
                <TableHead>{t("integrationSites.columns.code")}</TableHead>
                <TableHead>{t("integrationSites.columns.name")}</TableHead>
                <TableHead>{t("integrationSites.columns.currency")}</TableHead>
                <TableHead>{t("integrationSites.columns.status")}</TableHead>
                <TableHead>{t("integrationSites.columns.lineRoot")}</TableHead>
                <TableHead>{t("integrationSites.columns.walletUrl")}</TableHead>
                <TableHead>{t("integrationSites.columns.ssoSecret")}</TableHead>
                <TableHead>{t("integrationSites.columns.walletApiKey")}</TableHead>
                <TableHead className="sticky right-0 z-20 bg-muted w-14 text-center shadow-[-1px_0_0_rgba(203,213,225,0.7)]">{t("integrationSites.columns.actions")}</TableHead>
              </TableRow>
            </TableHeader>
            <TableBody>
              {items.map((row) => (
                <TableRow key={row.id}>
                  <TableCell>
                    <div className="flex max-w-[10rem] items-center gap-0.5">
                      <span className="truncate font-mono text-xs">{row.code}</span>
                      <CopyIconButton
                        label={t("integrationSites.copy")}
                        onClick={() => void copyText(t("integrationSites.columns.code"), row.code)}
                      />
                    </div>
                  </TableCell>
                  <TableCell>{row.name}</TableCell>
                  <TableCell className="font-mono text-xs">{row.currency_code}</TableCell>
                  <TableCell>
                    <AdminStatusBadge
                      tone={row.status === 1 ? "success" : "neutral"}
                    >
                      {row.status === 1
                        ? t("integrationSites.statusEnabled")
                        : t("integrationSites.statusDisabled")}
                    </AdminStatusBadge>
                  </TableCell>
                  <TableCell>
                    <AdminStatusBadge tone={row.has_line_root ? "success" : "neutral"}>
                      {row.has_line_root
                        ? t("integrationSites.lineRootBound")
                        : t("integrationSites.lineRootUnbound")}
                    </AdminStatusBadge>
                  </TableCell>
                  <TableCell>
                    <div className="flex max-w-[14rem] items-center gap-0.5">
                      <span className="truncate text-xs text-muted-foreground">
                        {row.wallet_api_url ?? "—"}
                      </span>
                      {row.wallet_api_url ? (
                        <CopyIconButton
                          label={t("integrationSites.copy")}
                          onClick={() =>
                            void copyText(
                              t("integrationSites.columns.walletUrl"),
                              row.wallet_api_url ?? "",
                            )
                          }
                        />
                      ) : null}
                    </div>
                  </TableCell>
                  <TableCell>
                    <MaskedValueWithCopy
                      configured={row.has_sso_secret}
                      masked={row.sso_secret_masked}
                      copyLabel={t("integrationSites.copy")}
                      canCopy={canManage}
                      copying={secretCopyBusyKey === `${row.id}:sso`}
                      onCopy={() => void copySiteSecret(row, "sso")}
                    />
                  </TableCell>
                  <TableCell>
                    <MaskedValueWithCopy
                      configured={row.has_wallet_api_key}
                      masked={row.wallet_api_key_masked}
                      copyLabel={t("integrationSites.copy")}
                      canCopy={canManage}
                      copying={secretCopyBusyKey === `${row.id}:wallet`}
                      onCopy={() => void copySiteSecret(row, "wallet")}
                    />
                  </TableCell>
                  <TableCell className="sticky right-0 z-10 bg-card text-center shadow-[-1px_0_0_rgba(203,213,225,0.7)]">
                    <AdminRowActionsMenu
                      busy={exportBusyId === row.id}
                      actions={[
                        {
                          key: "connectivity",
                          label: t("integrationSites.connectivityTest"),
                          icon: Link2,
                          hidden: !canManage,
                          onClick: () => openConnectivity(row),
                        },
                        {
                          key: "export",
                          label: t("integrationSites.exportParams"),
                          icon: Download,
                          disabled: exportBusyId === row.id,
                          onClick: () => void exportParameterSheet(row),
                        },
                        {
                          key: "edit",
                          label: t("integrationSites.edit"),
                          icon: Pencil,
                          hidden: !canManage,
                          onClick: () => void openEdit(row),
                        },
                        {
                          key: "rotate",
                          label: t("integrationSites.rotateSecrets"),
                          icon: ShieldAlert,
                          destructive: true,
                          hidden: !canManage,
                          onClick: () => setRotateTarget(row),
                        },
                        {
                          key: "delete",
                          label: t("integrationSites.delete"),
                          icon: Trash2,
                          destructive: true,
                          hidden: !canManage,
                          onClick: () => setDeleteTarget(row),
                        },
                      ]}
                    />
                  </TableCell>
                </TableRow>
              ))}
            </TableBody>
          </Table>
          </div>
        )}
      </AdminPageCard>

      <Dialog open={dialogOpen} onOpenChange={setDialogOpen}>
        <DialogContent className="max-h-[90vh] max-w-lg overflow-y-auto">
          <DialogHeader>
            <DialogTitle>
              {mode === "create"
                ? t("integrationSites.dialogCreateTitle")
                : t("integrationSites.dialogEditTitle")}
            </DialogTitle>
            <DialogDescription>{t("integrationSites.dialogDescription")}</DialogDescription>
          </DialogHeader>
          <div className="grid gap-4 py-2">
            <div className="grid gap-2">
              <Label htmlFor="is-code">{t("integrationSites.fields.code")}</Label>
              <Input
                id="is-code"
                value={form.code}
                disabled={mode === "edit"}
                onChange={(e) => updateForm("code", e.target.value)}
                placeholder={t("integrationSites.placeholders.code")}
              />
              {mode === "edit" ? (
                <p className="text-xs text-muted-foreground">{t("integrationSites.codeImmutable")}</p>
              ) : null}
            </div>
            <div className="grid gap-2">
              <Label htmlFor="is-name">{t("integrationSites.fields.name")}</Label>
              <Input
                id="is-name"
                value={form.name}
                placeholder={t("integrationSites.placeholders.name")}
                onChange={(e) => updateForm("name", e.target.value)}
              />
            </div>
            {mode === "create" ? (
              <>
                <div className="rounded-lg border border-border/60 bg-muted/20 p-4">
                  <div className="mb-3">
                    <p className="text-sm font-medium text-foreground">
                      {t("integrationSites.adminAccountSectionTitle", {
                        defaultValue: "站点后台管理账号",
                      })}
                    </p>
                    <p className="mt-1 text-xs text-muted-foreground">
                      {t("integrationSites.adminAccountSectionDescription", {
                        defaultValue: "创建站点时将同步创建一个绑定该站点的后台管理账号。",
                      })}
                    </p>
                  </div>
                  <div className="grid gap-4">
                    <div className="grid grid-cols-2 gap-4">
                      <div className="grid gap-2">
                        <Label htmlFor="is-admin-username">
                          {t("integrationSites.fields.adminUsername", { defaultValue: "后台登录名" })}
                        </Label>
                        <Input
                          id="is-admin-username"
                          value={form.admin_username}
                          placeholder={t("integrationSites.placeholders.adminUsername", {
                            defaultValue: "请输入后台登录名",
                          })}
                          onChange={(e) => updateForm("admin_username", e.target.value)}
                        />
                      </div>
                      <div className="grid gap-2">
                        <Label htmlFor="is-admin-nickname">
                          {t("integrationSites.fields.adminNickname", { defaultValue: "账号昵称" })}
                        </Label>
                        <Input
                          id="is-admin-nickname"
                          value={form.admin_nickname}
                          placeholder={t("integrationSites.placeholders.adminNickname", {
                            defaultValue: "请输入账号昵称",
                          })}
                          onChange={(e) => updateForm("admin_nickname", e.target.value)}
                        />
                      </div>
                    </div>
                    <div className="grid grid-cols-2 gap-4">
                      <div className="grid gap-2">
                        <Label htmlFor="is-admin-password">
                          {t("integrationSites.fields.adminPassword", { defaultValue: "初始密码" })}
                        </Label>
                        <Input
                          id="is-admin-password"
                          type="password"
                          value={form.admin_password}
                          placeholder={t("integrationSites.placeholders.adminPassword", {
                            defaultValue: "至少 8 位",
                          })}
                          onChange={(e) => updateForm("admin_password", e.target.value)}
                        />
                      </div>
                      <div className="grid gap-2">
                        <Label htmlFor="is-admin-email">
                          {t("integrationSites.fields.adminEmail", { defaultValue: "邮箱（可选）" })}
                        </Label>
                        <Input
                          id="is-admin-email"
                          value={form.admin_email}
                          placeholder={t("integrationSites.placeholders.adminEmail", {
                            defaultValue: "请输入邮箱",
                          })}
                          onChange={(e) => updateForm("admin_email", e.target.value)}
                        />
                      </div>
                    </div>
                  </div>
                </div>
              </>
            ) : null}
            <div className="grid grid-cols-2 gap-4">
              <div className="grid gap-2">
                <Label htmlFor="is-currency">{t("integrationSites.fields.currency")}</Label>
                <Input
                  id="is-currency"
                  value={form.currency_code}
                  placeholder={t("integrationSites.placeholders.currency")}
                  onChange={(e) => updateForm("currency_code", e.target.value)}
                />
              </div>
              <div className="grid gap-2">
                <Label htmlFor="is-status">{t("integrationSites.fields.status")}</Label>
                <select
                  id="is-status"
                  className="flex h-9 w-full rounded-md border border-input bg-transparent px-3 py-1 text-sm"
                  value={form.status}
                  onChange={(e) => updateForm("status", Number(e.target.value))}
                >
                  <option value={1}>{t("integrationSites.statusEnabled")}</option>
                  <option value={0}>{t("integrationSites.statusDisabled")}</option>
                </select>
              </div>
            </div>
            <div className="grid gap-2">
              <Label htmlFor="is-wallet-url">{t("integrationSites.fields.walletApiUrl")}</Label>
              <Input
                id="is-wallet-url"
                value={form.wallet_api_url}
                placeholder={t("integrationSites.placeholders.walletApiUrl")}
                onChange={(e) => updateForm("wallet_api_url", e.target.value)}
              />
            </div>
            <div className="grid gap-2">
              <Label htmlFor="is-origins">{t("integrationSites.fields.iframeOrigins")}</Label>
              <Textarea
                id="is-origins"
                rows={3}
                value={form.iframe_allowed_origins}
                onChange={(e) => updateForm("iframe_allowed_origins", e.target.value)}
                placeholder={t("integrationSites.placeholders.iframeOrigins")}
              />
            </div>
            <div className="grid gap-2">
              <Label htmlFor="is-notes">{t("integrationSites.fields.notes")}</Label>
              <Textarea
                id="is-notes"
                rows={2}
                value={form.notes}
                placeholder={t("integrationSites.placeholders.notes")}
                onChange={(e) => updateForm("notes", e.target.value)}
              />
            </div>
          </div>
          <DialogFooter>
            <Button type="button" variant="outline" onClick={() => setDialogOpen(false)}>
              {t("integrationSites.cancel")}
            </Button>
            {canManage ? (
              <Button type="button" disabled={saving} onClick={() => void handleSubmit()}>
                {saving ? t("integrationSites.saving") : t("integrationSites.save")}
              </Button>
            ) : null}
          </DialogFooter>
        </DialogContent>
      </Dialog>

      <Dialog open={rotateTarget !== null} onOpenChange={(open) => !open && setRotateTarget(null)}>
        <DialogContent>
          <DialogHeader>
            <DialogTitle>{t("integrationSites.rotateConfirmTitle")}</DialogTitle>
            <DialogDescription>
              {t("integrationSites.rotateConfirmDescription", {
                code: rotateTarget?.code ?? "",
              })}
            </DialogDescription>
          </DialogHeader>
          <DialogFooter>
            <Button type="button" variant="outline" onClick={() => setRotateTarget(null)}>
              {t("integrationSites.cancel")}
            </Button>
            <Button
              type="button"
              variant="destructive"
              disabled={rotateBusy}
              onClick={() => void confirmRotate()}
            >
              {rotateBusy ? t("integrationSites.saving") : t("integrationSites.rotateConfirm")}
            </Button>
          </DialogFooter>
        </DialogContent>
      </Dialog>

      <Dialog open={deleteTarget !== null} onOpenChange={(open) => !open && setDeleteTarget(null)}>
        <DialogContent>
          <DialogHeader>
            <DialogTitle>{t("integrationSites.deleteConfirmTitle")}</DialogTitle>
            <DialogDescription>
              {t("integrationSites.deleteConfirmDescription", {
                code: deleteTarget?.code ?? "",
                name: deleteTarget?.name ?? "",
              })}
            </DialogDescription>
          </DialogHeader>
          <DialogFooter>
            <Button type="button" variant="outline" onClick={() => setDeleteTarget(null)}>
              {t("integrationSites.cancel")}
            </Button>
            <Button
              type="button"
              variant="destructive"
              disabled={deleteBusy}
              onClick={() => void confirmDelete()}
            >
              {deleteBusy ? t("integrationSites.deleting") : t("integrationSites.deleteConfirm")}
            </Button>
          </DialogFooter>
        </DialogContent>
      </Dialog>

      <Dialog
        open={connectivityTarget !== null}
        onOpenChange={(open) => {
          if (!open) {
            setConnectivityTarget(null);
            setConnectivityResult(null);
          }
        }}
      >
        <DialogContent className="max-w-lg">
          <DialogHeader>
            <DialogTitle>{t("integrationSites.connectivityTitle")}</DialogTitle>
            <DialogDescription>
              {t("integrationSites.connectivityDescription", {
                code: connectivityTarget?.code ?? "",
              })}
            </DialogDescription>
          </DialogHeader>
          <div className="grid gap-4 py-2">
            <div className="grid gap-2">
              <Label htmlFor="ct-player">{t("integrationSites.connectivityPlayerId")}</Label>
              <Input
                id="ct-player"
                value={connectivityPlayerId}
                onChange={(e) => setConnectivityPlayerId(e.target.value)}
                placeholder={t("integrationSites.placeholders.connectivityPlayerId")}
              />
            </div>
            <div className="grid gap-2">
              <Label htmlFor="ct-currency">{t("integrationSites.fields.currency")}</Label>
              <Input
                id="ct-currency"
                value={connectivityCurrency}
                placeholder={t("integrationSites.placeholders.currency")}
                onChange={(e) => setConnectivityCurrency(e.target.value)}
              />
            </div>
            {connectivityResult ? (
              <div className="rounded-md border bg-muted/40 p-3 text-xs font-mono whitespace-pre-wrap break-all">
                {JSON.stringify(connectivityResult.probe, null, 2)}
              </div>
            ) : null}
          </div>
          <DialogFooter>
            <Button type="button" variant="outline" onClick={() => setConnectivityTarget(null)}>
              {t("integrationSites.cancel")}
            </Button>
            <Button
              type="button"
              disabled={!canManage || connectivityBusy || connectivityPlayerId.trim() === ""}
              onClick={() => void runConnectivityTest()}
            >
              {connectivityBusy
                ? t("integrationSites.connectivityRunning")
                : t("integrationSites.connectivityRun")}
            </Button>
          </DialogFooter>
        </DialogContent>
      </Dialog>

      <Dialog open={secretsDialog !== null} onOpenChange={(open) => !open && setSecretsDialog(null)}>
        <DialogContent>
          <DialogHeader>
            <DialogTitle>{t("integrationSites.secretsTitle")}</DialogTitle>
            <DialogDescription>
              {t("integrationSites.secretsDescription", { code: secretsDialog?.siteCode ?? "" })}
            </DialogDescription>
          </DialogHeader>
          {secretsDialog ? (
            <div className="space-y-4">
              <div className="space-y-2">
                <Label>{t("integrationSites.fields.ssoSecret")}</Label>
                <div className="flex gap-2">
                  <Input readOnly value={secretsDialog.secrets.sso_jwt_secret} className="font-mono text-xs" />
                  <CopyIconButton
                    label={t("integrationSites.copy")}
                    onClick={() =>
                      void copyText(
                        t("integrationSites.fields.ssoSecret"),
                        secretsDialog.secrets.sso_jwt_secret,
                      )
                    }
                  />
                </div>
              </div>
              <div className="space-y-2">
                <Label>{t("integrationSites.fields.walletApiKey")}</Label>
                <div className="flex gap-2">
                  <Input readOnly value={secretsDialog.secrets.wallet_api_key} className="font-mono text-xs" />
                  <CopyIconButton
                    label={t("integrationSites.copy")}
                    onClick={() =>
                      void copyText(
                        t("integrationSites.fields.walletApiKey"),
                        secretsDialog.secrets.wallet_api_key,
                      )
                    }
                  />
                </div>
              </div>
            </div>
          ) : null}
          <DialogFooter>
            <Button type="button" onClick={() => setSecretsDialog(null)}>
              {t("integrationSites.secretsDismiss")}
            </Button>
          </DialogFooter>
        </DialogContent>
      </Dialog>
    </>
  );
}
