"use client";

import { useCallback, useEffect, useMemo, useState } from "react";
import { useTranslations } from "next-intl";
import { Button, Card, Modal } from "@/shared/components";

type ProxyItem = {
  id: string;
  name: string;
  type: string;
  host: string;
  port: number;
  username?: string | null;
  password?: string | null;
  region?: string | null;
  notes?: string | null;
  status?: string;
};

type UsageInfo = {
  count: number;
  assignments: Array<{ scope: string; scopeId: string | null }>;
};

type HealthInfo = {
  proxyId: string;
  totalRequests: number;
  successRate: number | null;
  avgLatencyMs: number | null;
  lastSeenAt: string | null;
};

type TestResult = {
  success: boolean;
  publicIp?: string;
  latencyMs?: number;
  country?: string;
  error?: string;
};

type ParsedProxyEntry = {
  name: string;
  host: string;
  port: number;
  username: string;
  password: string;
  type: string;
  region: string;
  status: string;
  notes: string;
};

type ParseError = {
  line: number;
  reason: string;
};

const EMPTY_FORM = {
  id: "",
  name: "",
  type: "http",
  host: "",
  port: "8080",
  username: "",
  password: "",
  region: "",
  notes: "",
  status: "active",
};

const BULK_IMPORT_TEMPLATE = `# Proxy Bulk Import
# Format: NAME|HOST|PORT|USERNAME|PASSWORD|TYPE|REGION|STATUS|NOTES
# Required: NAME, HOST, PORT
# Optional: USERNAME, PASSWORD, TYPE (http|https|socks5, default: socks5), REGION, STATUS (active|inactive, default: active), NOTES
# Lines starting with # are ignored. Existing proxies (same host+port) will be updated.
#
# SOCKS5 examples:
# proxy-us|138.99.147.218|50101|myuser|mypass|socks5|US-East|active|US production proxy
# proxy-eu|200.234.177.62|50101|myuser|mypass|socks5|EU-West
#
# HTTP/HTTPS examples:
# http-proxy|10.0.0.50|8080|||http||active|Internal HTTP proxy
# https-proxy|proxy.example.com|443|admin|secret123|https|US|active
`;

const VALID_TYPES = new Set(["http", "https", "socks5"]);
const VALID_STATUSES = new Set(["active", "inactive"]);

function parseBulkImportText(text: string): {
  entries: ParsedProxyEntry[];
  errors: ParseError[];
  skipped: number;
} {
  const lines = text.split("\n");
  const entries: ParsedProxyEntry[] = [];
  const errors: ParseError[] = [];
  let skipped = 0;

  for (let i = 0; i < lines.length; i++) {
    const raw = lines[i].trim();
    if (!raw || raw.startsWith("#")) {
      skipped++;
      continue;
    }

    const parts = raw.split("|").map((p) => p.trim());
    const [name, host, portStr, username, password, type, region, status, notes] = parts;
    const lineNum = i + 1;

    if (!name) {
      errors.push({ line: lineNum, reason: "bulkImportErrorMissingName" });
      continue;
    }
    if (!host) {
      errors.push({ line: lineNum, reason: "bulkImportErrorMissingHost" });
      continue;
    }
    const port = Number(portStr);
    if (!portStr || isNaN(port) || port < 1 || port > 65535) {
      errors.push({ line: lineNum, reason: "bulkImportErrorInvalidPort" });
      continue;
    }
    const normalizedType = (type || "socks5").toLowerCase();
    if (!VALID_TYPES.has(normalizedType)) {
      errors.push({ line: lineNum, reason: "bulkImportErrorInvalidType" });
      continue;
    }
    const normalizedStatus = (status || "active").toLowerCase();
    if (!VALID_STATUSES.has(normalizedStatus)) {
      errors.push({ line: lineNum, reason: "bulkImportErrorInvalidStatus" });
      continue;
    }

    entries.push({
      name,
      host,
      port,
      username: username || "",
      password: password || "",
      type: normalizedType,
      region: region || "",
      status: normalizedStatus,
      notes: notes || "",
    });
  }

  return { entries, errors, skipped };
}

export default function ProxyRegistryManager() {
  const t = useTranslations("proxyRegistry");
  const [items, setItems] = useState<ProxyItem[]>([]);
  const [loading, setLoading] = useState(false);
  const [error, setError] = useState<string | null>(null);

  const [modalOpen, setModalOpen] = useState(false);
  const [saving, setSaving] = useState(false);
  const [form, setForm] = useState(EMPTY_FORM);

  const [usageById, setUsageById] = useState<Record<string, UsageInfo>>({});
  const [healthById, setHealthById] = useState<Record<string, HealthInfo>>({});
  const [testById, setTestById] = useState<Record<string, TestResult | null>>({});
  const [testingId, setTestingId] = useState<string | null>(null);
  const [migrating, setMigrating] = useState(false);
  const [bulkOpen, setBulkOpen] = useState(false);
  const [bulkSaving, setBulkSaving] = useState(false);
  const [bulkScope, setBulkScope] = useState("provider");
  const [bulkScopeIds, setBulkScopeIds] = useState("");
  const [bulkProxyId, setBulkProxyId] = useState("");

  // Bulk Import state
  const [bulkImportOpen, setBulkImportOpen] = useState(false);
  const [bulkImportText, setBulkImportText] = useState(BULK_IMPORT_TEMPLATE);
  const [bulkImportParsed, setBulkImportParsed] = useState<ParsedProxyEntry[]>([]);
  const [bulkImportErrors, setBulkImportErrors] = useState<ParseError[]>([]);
  const [bulkImportSkipped, setBulkImportSkipped] = useState(0);
  const [bulkImportParsedOnce, setBulkImportParsedOnce] = useState(false);
  const [bulkImporting, setBulkImporting] = useState(false);
  const [bulkImportResult, setBulkImportResult] = useState<{
    created: number;
    updated: number;
    failed: number;
  } | null>(null);

  const editingId = useMemo(() => form.id || "", [form.id]);

  const loadHealth = useCallback(async () => {
    try {
      const res = await fetch("/api/settings/proxies/health?hours=24");
      const data = await res.json().catch(() => ({}));
      if (!res.ok) return;
      const entries = Array.isArray(data?.items) ? data.items : [];
      const mapped = Object.fromEntries(
        entries.map((entry: HealthInfo) => [entry.proxyId, entry])
      ) as Record<string, HealthInfo>;
      setHealthById(mapped);
    } catch {
      // ignore health loading errors in UI
    }
  }, []);

  const loadAllUsage = useCallback(async (proxyIds: string[]) => {
    if (!proxyIds.length) return;
    try {
      const results = await Promise.all(
        proxyIds.map((id) =>
          fetch(`/api/settings/proxies/assignments?proxyId=${encodeURIComponent(id)}`)
            .then((r) => (r.ok ? r.json() : null))
            .then((data) => {
              const rawAssignments: Array<{ scope: string; scopeId: string | null }> =
                Array.isArray(data?.items) ? data.items : [];
              // Deduplicate by scope+scopeId — prevents double-counting when both
              // a provider-scope and account-scope row exist for the same proxy
              const seen = new Set<string>();
              const assignments = rawAssignments.filter((a) => {
                const key = `${a.scope}:${a.scopeId ?? ""}`;
                if (seen.has(key)) return false;
                seen.add(key);
                return true;
              });
              return [id, { count: assignments.length, assignments }] as [string, UsageInfo];
            })
            .catch(() => [id, { count: 0, assignments: [] }] as [string, UsageInfo])
        )
      );
      setUsageById(Object.fromEntries(results));
    } catch {
      // ignore
    }
  }, []);

  const load = useCallback(async () => {
    setLoading(true);
    setError(null);
    try {
      const res = await fetch("/api/settings/proxies");
      const data = await res.json().catch(() => ({}));
      if (!res.ok) {
        setError(data?.error?.message || t("errorLoadFailed"));
        setItems([]);
        return;
      }
      const loaded: ProxyItem[] = Array.isArray(data?.items) ? data.items : [];
      setItems(loaded);
      const ids = loaded.map((p) => p.id).filter(Boolean);
      void loadHealth();
      void loadAllUsage(ids);
    } catch (e: any) {
      setError(e?.message || t("errorLoadFailed"));
      setItems([]);
    } finally {
      setLoading(false);
    }
  }, [loadHealth, loadAllUsage, t]);

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

  useEffect(() => {
    if (items.length > 0 && !bulkProxyId) {
      setBulkProxyId(items[0].id);
    }
  }, [items, bulkProxyId]);

  const openCreate = () => {
    setForm(EMPTY_FORM);
    setModalOpen(true);
  };

  const openEdit = (item: ProxyItem) => {
    setForm({
      id: item.id,
      name: item.name || "",
      type: item.type || "http",
      host: item.host || "",
      port: String(item.port || 8080),
      username: "",
      password: "",
      region: item.region || "",
      notes: item.notes || "",
      status: item.status || "active",
    });
    setModalOpen(true);
  };

  const loadUsage = async (proxyId: string) => {
    try {
      const res = await fetch(
        `/api/settings/proxies/assignments?proxyId=${encodeURIComponent(proxyId)}`
      );
      const data = await res.json().catch(() => ({}));
      if (!res.ok) return;
      const rawAssignments: Array<{ scope: string; scopeId: string | null }> = Array.isArray(
        data?.items
      )
        ? data.items
        : [];
      const seen = new Set<string>();
      const assignments = rawAssignments.filter((a) => {
        const key = `${a.scope}:${a.scopeId ?? ""}`;
        if (seen.has(key)) return false;
        seen.add(key);
        return true;
      });
      setUsageById((prev) => ({
        ...prev,
        [proxyId]: { count: assignments.length, assignments },
      }));
    } catch {
      // ignore usage loading errors in UI
    }
  };

  const handleTestProxy = async (item: ProxyItem) => {
    if (testingId) return;
    setTestingId(item.id);
    setTestById((prev) => ({ ...prev, [item.id]: null }));
    try {
      const res = await fetch("/api/settings/proxy/test", {
        method: "POST",
        headers: { "Content-Type": "application/json" },
        body: JSON.stringify({
          proxyId: item.id,
          proxy: {
            type: item.type || "http",
            host: item.host,
            port: String(item.port || 8080),
          },
        }),
      });
      const data = await res.json().catch(() => ({}));
      if (!res.ok) {
        setTestById((prev) => ({
          ...prev,
          [item.id]: { success: false, error: data?.error?.message || t("failed") },
        }));
        return;
      }
      setTestById((prev) => ({ ...prev, [item.id]: { success: true, ...data } }));
    } catch (e: any) {
      setTestById((prev) => ({ ...prev, [item.id]: { success: false, error: e?.message } }));
    } finally {
      setTestingId(null);
    }
  };

  const handleSave = async () => {
    if (!(form.name || "").trim() || !(form.host || "").trim()) {
      setError(t("errorNameHostRequired"));
      return;
    }

    setSaving(true);
    setError(null);

    const normalizedUsername = (form.username || "").trim();
    const normalizedPassword = (form.password || "").trim();

    const payload: Record<string, unknown> = {
      ...(editingId ? { id: editingId } : {}),
      name: (form.name || "").trim(),
      type: form.type,
      host: (form.host || "").trim(),
      port: Number(form.port || 8080),
      region: (form.region || "").trim() || null,
      notes: (form.notes || "").trim() || null,
      status: form.status,
    };
    if (!editingId || normalizedUsername.length > 0) {
      payload.username = normalizedUsername;
    }
    if (!editingId || normalizedPassword.length > 0) {
      payload.password = normalizedPassword;
    }

    try {
      const res = await fetch("/api/settings/proxies", {
        method: editingId ? "PATCH" : "POST",
        headers: { "Content-Type": "application/json" },
        body: JSON.stringify(payload),
      });
      const data = await res.json().catch(() => ({}));
      if (!res.ok) {
        setError(data?.error?.message || t("errorSaveFailed"));
        return;
      }

      setModalOpen(false);
      setForm(EMPTY_FORM);
      await load();
    } catch (e: any) {
      setError(e?.message || t("errorSaveFailed"));
    } finally {
      setSaving(false);
    }
  };

  const handleDelete = async (id: string) => {
    try {
      const res = await fetch(`/api/settings/proxies?id=${encodeURIComponent(id)}`, {
        method: "DELETE",
      });

      if (res.ok) {
        await load();
        return;
      }

      const payload = await res.json().catch(() => ({}));
      const inUse = res.status === 409;
      if (inUse) {
        const ok = window.confirm(t("errorForceDeleteConfirm"));
        if (!ok) return;

        const forceRes = await fetch(`/api/settings/proxies?id=${encodeURIComponent(id)}&force=1`, {
          method: "DELETE",
        });

        if (!forceRes.ok) {
          const forcePayload = await forceRes.json().catch(() => ({}));
          setError(forcePayload?.error?.message || t("errorDeleteFailed"));
          return;
        }

        await load();
        return;
      }

      setError(payload?.error?.message || t("errorDeleteFailed"));
    } catch (e: any) {
      setError(e?.message || t("errorDeleteFailed"));
    }
  };

  const handleMigrate = async () => {
    setMigrating(true);
    setError(null);
    try {
      const res = await fetch("/api/settings/proxies/migrate", {
        method: "POST",
        headers: { "Content-Type": "application/json" },
        body: JSON.stringify({ force: false }),
      });
      const data = await res.json().catch(() => ({}));
      if (!res.ok) {
        setError(data?.error?.message || t("errorMigrateFailed"));
        return;
      }
      await load();
    } catch (e: any) {
      setError(e?.message || t("errorMigrateFailed"));
    } finally {
      setMigrating(false);
    }
  };

  const handleBulkAssign = async () => {
    setBulkSaving(true);
    setError(null);
    try {
      const scopeIds =
        bulkScope === "global"
          ? []
          : bulkScopeIds
              .split(/[\n,]/g)
              .map((part) => part.trim())
              .filter(Boolean);

      const res = await fetch("/api/settings/proxies/bulk-assign", {
        method: "PUT",
        headers: { "Content-Type": "application/json" },
        body: JSON.stringify({
          scope: bulkScope,
          scopeIds,
          proxyId: bulkProxyId || null,
        }),
      });
      const payload = await res.json().catch(() => ({}));
      if (!res.ok) {
        setError(payload?.error?.message || t("errorBulkFailed"));
        return;
      }

      setBulkOpen(false);
      setBulkScopeIds("");
      await load();
    } catch (e: any) {
      setError(e?.message || t("errorBulkFailed"));
    } finally {
      setBulkSaving(false);
    }
  };

  const handleBulkImportParse = () => {
    const { entries, errors, skipped } = parseBulkImportText(bulkImportText);
    setBulkImportParsed(entries);
    setBulkImportErrors(errors);
    setBulkImportSkipped(skipped);
    setBulkImportParsedOnce(true);
    setBulkImportResult(null);
  };

  const handleBulkImportExecute = async () => {
    if (bulkImportParsed.length === 0) return;
    if (bulkImportParsed.length > 100) {
      setError(t("bulkImportMaxExceeded"));
      return;
    }

    setBulkImporting(true);
    setError(null);
    setBulkImportResult(null);

    try {
      const payload = {
        items: bulkImportParsed.map((entry) => ({
          name: entry.name,
          type: entry.type,
          host: entry.host,
          port: entry.port,
          username: entry.username || undefined,
          password: entry.password || undefined,
          region: entry.region || null,
          notes: entry.notes || null,
          status: entry.status as "active" | "inactive",
        })),
      };

      const res = await fetch("/api/settings/proxies/bulk-import", {
        method: "POST",
        headers: { "Content-Type": "application/json" },
        body: JSON.stringify(payload),
      });
      const data = await res.json().catch(() => ({}));

      if (!res.ok) {
        setError(data?.error?.message || t("errorSaveFailed"));
        return;
      }

      setBulkImportResult({
        created: data.created || 0,
        updated: data.updated || 0,
        failed: data.failed || 0,
      });

      await load();
    } catch (e: any) {
      setError(e?.message || t("errorSaveFailed"));
    } finally {
      setBulkImporting(false);
    }
  };

  const openBulkImport = () => {
    setBulkImportText(BULK_IMPORT_TEMPLATE);
    setBulkImportParsed([]);
    setBulkImportErrors([]);
    setBulkImportSkipped(0);
    setBulkImportParsedOnce(false);
    setBulkImportResult(null);
    setBulkImportOpen(true);
  };

  return (
    <>
      <Card className="p-6">
        <div className="flex items-center justify-between gap-3 mb-4">
          <div>
            <h3 className="text-lg font-semibold">{t("title")}</h3>
            <p className="text-sm text-text-muted">{t("description")}</p>
          </div>
          <div className="flex items-center gap-2">
            <Button
              size="sm"
              variant="secondary"
              icon="upgrade"
              onClick={handleMigrate}
              loading={migrating}
              data-testid="proxy-registry-import-legacy"
            >
              {t("importLegacy")}
            </Button>
            <Button
              size="sm"
              variant="secondary"
              icon="upload_file"
              onClick={openBulkImport}
              data-testid="proxy-registry-open-bulk-import"
            >
              {t("bulkImport")}
            </Button>
            <Button
              size="sm"
              variant="secondary"
              icon="account_tree"
              onClick={() => setBulkOpen(true)}
              data-testid="proxy-registry-open-bulk"
            >
              {t("bulkAssign")}
            </Button>
            <Button
              size="sm"
              icon="add"
              onClick={openCreate}
              data-testid="proxy-registry-open-create"
            >
              {t("addProxy")}
            </Button>
          </div>
        </div>

        {error && (
          <div className="mb-3 px-3 py-2 rounded border border-red-500/30 bg-red-500/10 text-sm text-red-400">
            {error}
          </div>
        )}

        {loading ? (
          <div className="text-sm text-text-muted">{t("loading")}</div>
        ) : items.length === 0 ? (
          <div className="text-sm text-text-muted">{t("noProxies")}</div>
        ) : (
          <div className="overflow-x-auto">
            <table className="w-full text-sm">
              <thead>
                <tr className="text-left text-text-muted border-b border-border">
                  <th className="py-2 pr-3">{t("tableName")}</th>
                  <th className="py-2 pr-3">{t("tableEndpoint")}</th>
                  <th className="py-2 pr-3">{t("tableStatus")}</th>
                  <th className="py-2 pr-3">{t("tableHealth")}</th>
                  <th className="py-2 pr-3">{t("tableUsage")}</th>
                  <th className="py-2">{t("tableActions")}</th>
                </tr>
              </thead>
              <tbody>
                {items.map((item) => {
                  const usage = usageById[item.id];
                  const health = healthById[item.id];
                  return (
                    <tr key={item.id} className="border-b border-border/60">
                      <td className="py-2 pr-3">
                        <div className="font-medium text-text-main">{item.name}</div>
                        {item.region && (
                          <div className="text-xs text-text-muted">{item.region}</div>
                        )}
                      </td>
                      <td className="py-2 pr-3 font-mono text-xs text-text-muted">
                        {item.type}://{item.host}:{item.port}
                      </td>
                      <td className="py-2 pr-3">
                        <span className="text-xs px-2 py-1 rounded border border-border bg-bg-subtle">
                          {item.status === "inactive" ? t("statusInactive") : t("statusActive")}
                        </span>
                      </td>
                      <td className="py-2 pr-3 text-xs text-text-muted">
                        <div className="flex flex-col gap-0.5">
                          {testById[item.id] ? (
                            testById[item.id]!.success ? (
                              <>
                                <span className="text-emerald-400">
                                  ✓ {testById[item.id]!.publicIp}
                                </span>
                                {testById[item.id]!.latencyMs && (
                                  <span>{testById[item.id]!.latencyMs}ms</span>
                                )}
                              </>
                            ) : (
                              <span className="text-red-400">
                                ✗ {testById[item.id]!.error || t("failed")}
                              </span>
                            )
                          ) : health ? (
                            <>
                              <span>{t("successRate", { rate: health.successRate ?? 0 })}</span>
                              <span>
                                {t("avgLatency", { latency: health.avgLatencyMs ?? "-" })}
                              </span>
                            </>
                          ) : (
                            <span>—</span>
                          )}
                        </div>
                      </td>
                      <td className="py-2 pr-3 text-xs text-text-muted">
                        {usageById[item.id] != null
                          ? t("assignmentsCount", { count: usageById[item.id].count })
                          : t("noData")}
                      </td>
                      <td className="py-2">
                        <div className="flex items-center gap-1">
                          <Button
                            size="sm"
                            variant="ghost"
                            icon="speed"
                            onClick={() => void handleTestProxy(item)}
                            loading={testingId === item.id}
                          >
                            {t("test")}
                          </Button>
                          <Button
                            size="sm"
                            variant="ghost"
                            icon="edit"
                            onClick={() => openEdit(item)}
                          >
                            {t("edit")}
                          </Button>
                          <Button
                            size="sm"
                            variant="ghost"
                            icon="delete"
                            onClick={() => void handleDelete(item.id)}
                            className="!text-red-400"
                          >
                            {t("delete")}
                          </Button>
                        </div>
                      </td>
                    </tr>
                  );
                })}
              </tbody>
            </table>
          </div>
        )}
      </Card>

      <Modal
        isOpen={modalOpen}
        onClose={() => {
          if (!saving) setModalOpen(false);
        }}
        title={editingId ? t("modalEditTitle") : t("modalCreateTitle")}
        maxWidth="lg"
      >
        <form
          className="flex flex-col gap-3"
          onSubmit={(e) => {
            e.preventDefault();
            handleSave();
          }}
          autoComplete="off"
          data-1p-ignore="true"
        >
          <div className="grid grid-cols-2 gap-3">
            <div>
              <label className="text-xs text-text-muted mb-1 block">{t("labelName")}</label>
              <input
                data-testid="proxy-registry-name-input"
                className="w-full px-3 py-2 rounded bg-bg-subtle border border-border"
                value={form.name}
                onChange={(e) => setForm((prev) => ({ ...prev, name: e.target.value }))}
              />
            </div>
            <div>
              <label className="text-xs text-text-muted mb-1 block">{t("labelType")}</label>
              <select
                className="w-full px-3 py-2 rounded bg-bg-subtle border border-border"
                value={form.type}
                onChange={(e) => setForm((prev) => ({ ...prev, type: e.target.value }))}
              >
                <option value="http">HTTP</option>
                <option value="https">HTTPS</option>
                <option value="socks5">SOCKS5</option>
              </select>
            </div>
            <div>
              <label className="text-xs text-text-muted mb-1 block">{t("labelHost")}</label>
              <input
                data-testid="proxy-registry-host-input"
                className="w-full px-3 py-2 rounded bg-bg-subtle border border-border"
                value={form.host}
                onChange={(e) => setForm((prev) => ({ ...prev, host: e.target.value }))}
              />
            </div>
            <div>
              <label className="text-xs text-text-muted mb-1 block">{t("labelPort")}</label>
              <input
                className="w-full px-3 py-2 rounded bg-bg-subtle border border-border"
                value={form.port}
                onChange={(e) => setForm((prev) => ({ ...prev, port: e.target.value }))}
              />
            </div>
            <div>
              <label className="text-xs text-text-muted mb-1 block">{t("labelUsername")}</label>
              <input
                className="w-full px-3 py-2 rounded bg-bg-subtle border border-border"
                value={form.username}
                placeholder={editingId ? t("usernamePlaceholderEdit") : ""}
                onChange={(e) => setForm((prev) => ({ ...prev, username: e.target.value }))}
              />
            </div>
            <div>
              <label className="text-xs text-text-muted mb-1 block">{t("labelPassword")}</label>
              <input
                type="password"
                className="w-full px-3 py-2 rounded bg-bg-subtle border border-border"
                value={form.password}
                placeholder={editingId ? t("passwordPlaceholderEdit") : ""}
                onChange={(e) => setForm((prev) => ({ ...prev, password: e.target.value }))}
              />
            </div>
            <div>
              <label className="text-xs text-text-muted mb-1 block">{t("labelRegion")}</label>
              <input
                className="w-full px-3 py-2 rounded bg-bg-subtle border border-border"
                value={form.region}
                onChange={(e) => setForm((prev) => ({ ...prev, region: e.target.value }))}
              />
            </div>
            <div>
              <label className="text-xs text-text-muted mb-1 block">{t("labelStatus")}</label>
              <select
                className="w-full px-3 py-2 rounded bg-bg-subtle border border-border"
                value={form.status}
                onChange={(e) => setForm((prev) => ({ ...prev, status: e.target.value }))}
              >
                <option value="active">{t("statusActive")}</option>
                <option value="inactive">{t("statusInactive")}</option>
              </select>
            </div>
          </div>

          <div>
            <label className="text-xs text-text-muted mb-1 block">{t("labelNotes")}</label>
            <textarea
              className="w-full px-3 py-2 rounded bg-bg-subtle border border-border"
              value={form.notes}
              onChange={(e) => setForm((prev) => ({ ...prev, notes: e.target.value }))}
              rows={3}
            />
          </div>

          <div className="flex items-center justify-end gap-2 pt-2 border-t border-border">
            <Button size="sm" variant="secondary" onClick={() => setModalOpen(false)}>
              {t("cancel")}
            </Button>
            <Button size="sm" icon="save" onClick={handleSave} loading={saving}>
              {t("save")}
            </Button>
          </div>
        </form>
      </Modal>

      <Modal
        isOpen={bulkOpen}
        onClose={() => {
          if (!bulkSaving) setBulkOpen(false);
        }}
        title={t("bulkProxyAssignment")}
        maxWidth="lg"
      >
        <div className="flex flex-col gap-3">
          <div className="grid grid-cols-2 gap-3">
            <div>
              <label className="text-xs text-text-muted mb-1 block">{t("labelScope")}</label>
              <select
                className="w-full px-3 py-2 rounded bg-bg-subtle border border-border"
                value={bulkScope}
                onChange={(e) => setBulkScope(e.target.value)}
              >
                <option value="global">{t("scopeGlobal")}</option>
                <option value="provider">{t("scopeProvider")}</option>
                <option value="account">{t("scopeAccount")}</option>
                <option value="combo">{t("scopeCombo")}</option>
              </select>
            </div>
            <div>
              <label className="text-xs text-text-muted mb-1 block">{t("labelProxy")}</label>
              <select
                className="w-full px-3 py-2 rounded bg-bg-subtle border border-border"
                value={bulkProxyId}
                onChange={(e) => setBulkProxyId(e.target.value)}
              >
                <option value="">{t("clearAssignment")}</option>
                {items.map((item) => (
                  <option key={item.id} value={item.id}>
                    {item.name} ({item.type}://{item.host}:{item.port})
                  </option>
                ))}
              </select>
            </div>
          </div>

          {bulkScope !== "global" && (
            <div>
              <label className="text-xs text-text-muted mb-1 block">{t("bulkLabelScopeIds")}</label>
              <textarea
                data-testid="proxy-registry-bulk-scopeids-input"
                className="w-full px-3 py-2 rounded bg-bg-subtle border border-border"
                rows={5}
                value={bulkScopeIds}
                onChange={(e) => setBulkScopeIds(e.target.value)}
                placeholder={t("bulkScopeIdsPlaceholder")}
              />
            </div>
          )}

          <div className="flex items-center justify-end gap-2 pt-2 border-t border-border">
            <Button size="sm" variant="secondary" onClick={() => setBulkOpen(false)}>
              {t("cancel")}
            </Button>
            <Button
              size="sm"
              icon="done_all"
              onClick={handleBulkAssign}
              loading={bulkSaving}
              data-testid="proxy-registry-bulk-apply"
            >
              {t("bulkApply")}
            </Button>
          </div>
        </div>
      </Modal>

      {/* Bulk Import Modal */}
      <Modal
        isOpen={bulkImportOpen}
        onClose={() => {
          if (!bulkImporting) setBulkImportOpen(false);
        }}
        title={t("bulkImportTitle")}
        maxWidth="xl"
      >
        <div className="flex flex-col gap-4">
          <p className="text-sm text-text-muted">{t("bulkImportDescription")}</p>

          <div>
            <textarea
              data-testid="proxy-registry-bulk-import-textarea"
              className="w-full px-3 py-2 rounded bg-bg-subtle border border-border font-mono text-xs leading-relaxed"
              rows={14}
              value={bulkImportText}
              onChange={(e) => {
                setBulkImportText(e.target.value);
                setBulkImportParsedOnce(false);
                setBulkImportResult(null);
              }}
              spellCheck={false}
            />
          </div>

          {/* Parse button */}
          <div className="flex items-center gap-3">
            <Button
              size="sm"
              variant="secondary"
              icon="search"
              onClick={handleBulkImportParse}
              data-testid="proxy-registry-bulk-import-parse"
            >
              {t("bulkImportParse")}
            </Button>

            {bulkImportParsedOnce && (
              <div className="flex items-center gap-3 text-xs">
                <span className="text-emerald-400">
                  {t("bulkImportParsed", { count: bulkImportParsed.length })}
                </span>
                <span className="text-text-muted">
                  {t("bulkImportSkipped", { count: bulkImportSkipped })}
                </span>
                {bulkImportErrors.length > 0 && (
                  <span className="text-red-400">
                    {t("bulkImportParseErrors", { count: bulkImportErrors.length })}
                  </span>
                )}
              </div>
            )}
          </div>

          {/* Parse errors */}
          {bulkImportErrors.length > 0 && (
            <div className="max-h-28 overflow-y-auto rounded border border-red-500/30 bg-red-500/10 p-2">
              {bulkImportErrors.map((err, idx) => (
                <div key={idx} className="text-xs text-red-400">
                  {t("bulkImportErrorLine", { line: err.line, reason: t(err.reason as any) })}
                </div>
              ))}
            </div>
          )}

          {/* Preview table */}
          {bulkImportParsedOnce && bulkImportParsed.length > 0 && (
            <div className="overflow-x-auto max-h-48 overflow-y-auto rounded border border-border">
              <table className="w-full text-xs">
                <thead>
                  <tr className="text-left text-text-muted border-b border-border bg-bg-subtle sticky top-0">
                    <th className="py-1.5 px-2">{t("tableName")}</th>
                    <th className="py-1.5 px-2">{t("labelType")}</th>
                    <th className="py-1.5 px-2">{t("labelHost")}</th>
                    <th className="py-1.5 px-2">{t("labelPort")}</th>
                    <th className="py-1.5 px-2">{t("labelUsername")}</th>
                    <th className="py-1.5 px-2">{t("labelRegion")}</th>
                    <th className="py-1.5 px-2">{t("labelStatus")}</th>
                  </tr>
                </thead>
                <tbody>
                  {bulkImportParsed.map((entry, idx) => (
                    <tr key={idx} className="border-b border-border/40">
                      <td className="py-1 px-2 font-medium text-text-main">{entry.name}</td>
                      <td className="py-1 px-2">
                        <span className="px-1.5 py-0.5 rounded bg-bg-subtle border border-border text-[10px]">
                          {entry.type}
                        </span>
                      </td>
                      <td className="py-1 px-2 font-mono text-text-muted">{entry.host}</td>
                      <td className="py-1 px-2 font-mono text-text-muted">{entry.port}</td>
                      <td className="py-1 px-2 text-text-muted">{entry.username || "—"}</td>
                      <td className="py-1 px-2 text-text-muted">{entry.region || "—"}</td>
                      <td className="py-1 px-2">
                        <span
                          className={
                            entry.status === "active" ? "text-emerald-400" : "text-text-muted"
                          }
                        >
                          {entry.status === "active" ? t("statusActive") : t("statusInactive")}
                        </span>
                      </td>
                    </tr>
                  ))}
                </tbody>
              </table>
            </div>
          )}

          {/* No valid entries warning */}
          {bulkImportParsedOnce &&
            bulkImportParsed.length === 0 &&
            bulkImportErrors.length === 0 && (
              <div className="text-sm text-amber-400">{t("bulkImportNoValidEntries")}</div>
            )}

          {/* Import result */}
          {bulkImportResult && (
            <div className="px-3 py-2 rounded border border-emerald-500/30 bg-emerald-500/10 text-sm text-emerald-400">
              {t("bulkImportSuccess", {
                created: bulkImportResult.created,
                updated: bulkImportResult.updated,
                failed: bulkImportResult.failed,
              })}
            </div>
          )}

          {/* Actions */}
          <div className="flex items-center justify-end gap-2 pt-2 border-t border-border">
            <Button size="sm" variant="secondary" onClick={() => setBulkImportOpen(false)}>
              {t("cancel")}
            </Button>
            <Button
              size="sm"
              icon="upload"
              onClick={handleBulkImportExecute}
              loading={bulkImporting}
              disabled={!bulkImportParsedOnce || bulkImportParsed.length === 0}
              data-testid="proxy-registry-bulk-import-execute"
            >
              {bulkImporting
                ? t("bulkImportImporting")
                : bulkImportParsed.length > 0
                  ? t("bulkImportImport", { count: bulkImportParsed.length })
                  : t("bulkImport")}
            </Button>
          </div>
        </div>
      </Modal>
    </>
  );
}
