"use client";

import type { RegistrarAccount } from "@domainops/shared-types";
import { App, Button, Input, Modal, Popconfirm, Switch, Table, Tag, Tooltip, Typography } from "antd";
import { ApiOutlined, DeleteOutlined, DollarOutlined, EditOutlined, InboxOutlined, PlusOutlined, SyncOutlined } from "@ant-design/icons";
import type { ColumnsType } from "antd/es/table";
import Link from "next/link";
import { useCallback, useEffect, useState } from "react";
import {
  archiveRegistrar,
  deleteRegistrar,
  listRegistrars,
  refreshRegistrarBalance,
  syncRegistrar,
  testRegistrarConnection,
  updateRegistrar,
} from "@/lib/api/acquire";
import { ApiError } from "@/lib/api/client";
import { SORT_DIRECTIONS, textCompare } from "@/lib/utils/sort";
import { useAuth } from "@/lib/auth/AuthProvider";
import { PAGE_SIZE_OPTIONS } from "@/lib/hooks/useServerPagination";
import { providerLabel } from "@/lib/utils/text";
import { PageGuide } from "@/components/features/PageGuide";
import { REGISTRARS_GUIDES } from "@/lib/guides/registrars";
import { RegistrarFormModal } from "./RegistrarFormModal";

export default function RegistrarsPage() {
  const { message, modal } = App.useApp();
  const { user: currentUser } = useAuth();
  const [accounts, setAccounts] = useState<RegistrarAccount[]>([]);
  const [archivingAccount, setArchivingAccount] = useState<RegistrarAccount | null>(null);
  const [archiveReason, setArchiveReason] = useState("");
  const [isArchiving, setIsArchiving] = useState(false);
  const [supportedProviders, setSupportedProviders] = useState<string[]>([]);
  const [egressIp, setEgressIp] = useState<string | null>(null);
  const [isLoading, setIsLoading] = useState(true);
  const [isFormOpen, setIsFormOpen] = useState(false);
  const [editingAccount, setEditingAccount] = useState<RegistrarAccount | null>(null);
  const [testingId, setTestingId] = useState<number | null>(null);
  const [refreshingBalanceId, setRefreshingBalanceId] = useState<number | null>(null);
  const [syncingId, setSyncingId] = useState<number | null>(null);
  const [togglingId, setTogglingId] = useState<number | null>(null);
  const [selectedIds, setSelectedIds] = useState<number[]>([]);
  const [isBulkWorking, setIsBulkWorking] = useState(false);

  const load = useCallback(async () => {
    setIsLoading(true);
    try {
      const response = await listRegistrars();
      setAccounts(response.accounts);
      setSupportedProviders(response.supported_providers);
      setEgressIp(response.egress_ip);
    } catch (err) {
      message.error(err instanceof ApiError ? err.message : "Couldn't load registrar accounts.");
    } finally {
      setIsLoading(false);
    }
  }, [message]);

  useEffect(() => {
    // eslint-disable-next-line react-hooks/set-state-in-effect
    void load();
  }, [load]);

  async function handleTest(account: RegistrarAccount) {
    setTestingId(account.id);
    try {
      await testRegistrarConnection(account.id);
      message.success("Connected successfully.");
    } catch (err) {
      message.error(err instanceof ApiError ? err.message : "Connection failed.");
    } finally {
      setTestingId(null);
      void load();
    }
  }

  async function handleRefreshBalance(account: RegistrarAccount) {
    setRefreshingBalanceId(account.id);
    try {
      await refreshRegistrarBalance(account.id);
      message.success("Balance refreshed.");
      void load();
    } catch (err) {
      message.error(err instanceof ApiError ? err.message : "Couldn't refresh the balance.");
    } finally {
      setRefreshingBalanceId(null);
    }
  }

  async function handleSync(account: RegistrarAccount) {
    setSyncingId(account.id);
    try {
      const result = await syncRegistrar(account.id);
      message.success(`Found ${result.domains_found} domain(s), added ${result.domains_added} new.`);
      void load();
    } catch (err) {
      message.error(err instanceof ApiError ? err.message : "Couldn't sync this account.");
    } finally {
      setSyncingId(null);
    }
  }

  async function handleToggleActive(account: RegistrarAccount, isActive: boolean) {
    setTogglingId(account.id);
    try {
      await updateRegistrar(account.id, { is_active: isActive });
      message.success(isActive ? "Enabled." : "Disabled.");
      void load();
    } catch (err) {
      message.error(err instanceof ApiError ? err.message : "Couldn't change that.");
    } finally {
      setTogglingId(null);
    }
  }

  function handleDelete(account: RegistrarAccount) {
    modal.confirm({
      title: `Permanently delete ${account.label}?`,
      content: "Domains already purchased through it stay in inventory; this just removes the account. This cannot be undone - prefer Archive unless you're certain.",
      okButtonProps: { danger: true },
      onOk: async () => {
        try {
          await deleteRegistrar(account.id);
          message.success(`${account.label} deleted.`);
          void load();
        } catch (err) {
          message.error(err instanceof ApiError ? err.message : "Couldn't delete that account.");
        }
      },
    });
  }

  async function handleArchive() {
    if (!archivingAccount || !archiveReason.trim()) return;
    setIsArchiving(true);
    try {
      await archiveRegistrar(archivingAccount.id, archiveReason.trim());
      message.success(`${archivingAccount.label} archived.`);
      setArchivingAccount(null);
      setArchiveReason("");
      void load();
    } catch (err) {
      message.error(err instanceof ApiError ? err.message : "Couldn't archive that account.");
    } finally {
      setIsArchiving(false);
    }
  }

  const selectedAccounts = accounts.filter((a) => selectedIds.includes(a.id));

  async function runBulk(targets: RegistrarAccount[], action: (a: RegistrarAccount) => Promise<unknown>, successLabel: string) {
    setIsBulkWorking(true);
    try {
      const results = await Promise.allSettled(targets.map(action));
      const succeeded = results.filter((r) => r.status === "fulfilled").length;
      const failed = results.length - succeeded;
      if (succeeded > 0) message.success(`${successLabel} for ${succeeded} account${succeeded === 1 ? "" : "s"}.`);
      if (failed > 0) message.error(`Failed for ${failed} account${failed === 1 ? "" : "s"}.`);
      setSelectedIds([]);
      void load();
    } finally {
      setIsBulkWorking(false);
    }
  }

  async function handleBulkEnable() {
    await runBulk(selectedAccounts.filter((a) => !a.is_active), (a) => updateRegistrar(a.id, { is_active: true }), "Enabled");
  }

  async function handleBulkDisable() {
    await runBulk(selectedAccounts.filter((a) => a.is_active), (a) => updateRegistrar(a.id, { is_active: false }), "Disabled");
  }

  async function handleBulkSync() {
    await runBulk(selectedAccounts, (a) => syncRegistrar(a.id), "Synced");
  }

  async function handleBulkDelete() {
    await runBulk(selectedAccounts, (a) => deleteRegistrar(a.id), "Deleted");
  }

  const columns: ColumnsType<RegistrarAccount> = [
    { title: "Label", dataIndex: "label", sorter: (a, b) => textCompare(a.label, b.label), sortDirections: SORT_DIRECTIONS, render: (v: string) => <span className="font-semibold">{v}</span> },
    { title: "Provider", dataIndex: "provider", sorter: (a, b) => textCompare(a.provider, b.provider), sortDirections: SORT_DIRECTIONS, render: (v: string, account) => providerLabel(v, account.provider_name) },
    { title: "API User", dataIndex: "api_user", render: (v: string | null) => v ?? "—" },
    { title: "Whitelist", dataIndex: "whitelisted_ips", render: (v: string | null) => v ?? "—" },
    { title: "Remarks", dataIndex: "notes", render: (v: string | null) => v ?? "—" },
    { title: "Domains", dataIndex: "domain_count" },
    {
      title: "Balance",
      render: (_, a) =>
        a.balance_cache ? `${a.balance_currency ?? ""} ${Number(a.balance_cache).toFixed(2)}`.trim() : "—",
    },
    {
      title: "Last Test",
      render: (_, a) =>
        a.last_test_succeeded === null ? "—" : (
          <Tag color={a.last_test_succeeded ? "green" : "red"}>{a.last_test_succeeded ? "OK" : "Failed"}</Tag>
        ),
    },
    {
      title: "Status",
      render: (_, a) => (
        <Switch checked={a.is_active} loading={togglingId === a.id} onChange={(checked) => handleToggleActive(a, checked)} />
      ),
    },
    {
      title: "Actions",
      render: (_, a) => (
        <div className="flex gap-2">
          <Tooltip title="Edit">
            <Button
              size="small"
              icon={<EditOutlined />}
              onClick={() => {
                setEditingAccount(a);
                setIsFormOpen(true);
              }}
              className="dms_registrars_edit_btn"
            />
          </Tooltip>
          <Tooltip title="Test Connection">
            <Button
              size="small"
              icon={<ApiOutlined />}
              loading={testingId === a.id}
              onClick={() => handleTest(a)}
              className="dms_registrars_test_connection_btn"
            />
          </Tooltip>
          <Tooltip title="Refresh Balance">
            <Button
              size="small"
              icon={<DollarOutlined />}
              loading={refreshingBalanceId === a.id}
              onClick={() => handleRefreshBalance(a)}
              className="dms_registrars_refresh_balance_btn"
            />
          </Tooltip>
          <Tooltip title="Sync Domains From Registrar">
            <Button
              size="small"
              icon={<SyncOutlined />}
              loading={syncingId === a.id}
              onClick={() => handleSync(a)}
              className="dms_registrars_sync_btn"
            />
          </Tooltip>
          <Tooltip title="Archive">
            <Button
              size="small"
              danger
              icon={<InboxOutlined />}
              onClick={() => setArchivingAccount(a)}
              className="dms_registrars_archive_btn"
            />
          </Tooltip>
          {currentUser?.is_crowned_or_above && (
            <Tooltip title="Permanently delete">
              <Button
                size="small"
                danger
                icon={<DeleteOutlined />}
                onClick={() => handleDelete(a)}
                className="dms_registrars_delete_btn"
              />
            </Tooltip>
          )}
        </div>
      ),
    },
  ];

  return (
    <div className="flex flex-col gap-4 page page-registrars">
      <div className="flex items-center justify-between">
        <div className="flex items-center gap-2">
          <Typography.Title level={4} style={{ margin: 0 }}>
            Registrars
          </Typography.Title>
          <PageGuide guides={REGISTRARS_GUIDES} label="Registrars guide" />
        </div>
        <div className="flex items-center gap-2">
          <Link href="/registrars/expiring">
            <Button className="dms_registrars_expiring_link_btn">Expiring Domains</Button>
          </Link>
          <Button
            type="primary"
            icon={<PlusOutlined />}
            onClick={() => {
              setEditingAccount(null);
              setIsFormOpen(true);
            }}
            className="dms_registrars_add_btn"
          >
            Add Registrar Account
          </Button>
        </div>
      </div>

      {!egressIp && (
        <Typography.Paragraph type="warning" style={{ marginBottom: 0 }}>
          NAMECHEAP_EGRESS_IP isn&apos;t set on the server yet, so every Namecheap call will fail regardless of
          the account&apos;s API key. The &quot;Whitelist&quot; column below is just your own note - it isn&apos;t
          sent to Namecheap. Set NAMECHEAP_EGRESS_IP in the API&apos;s .env to this server&apos;s real public IP,
          then whitelist that same IP at Namecheap under Profile → Tools → API Access.
        </Typography.Paragraph>
      )}

      {selectedIds.length > 0 && (
        <div className="flex items-center gap-2 flex-wrap dms_registrars_bulk_bar">
          <Typography.Text>{selectedIds.length} selected</Typography.Text>
          <Popconfirm title="Enable the selected accounts?" onConfirm={handleBulkEnable}>
            <Button size="small" loading={isBulkWorking} className="dms_registrars_bulk_enable_btn">
              Enable
            </Button>
          </Popconfirm>
          <Popconfirm title="Disable the selected accounts?" onConfirm={handleBulkDisable}>
            <Button size="small" loading={isBulkWorking} className="dms_registrars_bulk_disable_btn">
              Disable
            </Button>
          </Popconfirm>
          <Popconfirm title="Sync the selected accounts?" onConfirm={handleBulkSync}>
            <Button size="small" icon={<SyncOutlined />} loading={isBulkWorking} className="dms_registrars_bulk_sync_btn">
              Sync
            </Button>
          </Popconfirm>
          {currentUser?.is_crowned_or_above && (
            <Popconfirm title="Permanently delete the selected accounts?" onConfirm={handleBulkDelete}>
              <Button size="small" danger icon={<DeleteOutlined />} loading={isBulkWorking} className="dms_registrars_bulk_delete_btn">
                Delete
              </Button>
            </Popconfirm>
          )}
          <Button size="small" onClick={() => setSelectedIds([])} className="dms_registrars_bulk_clear_btn">
            Clear
          </Button>
        </div>
      )}

      <Table<RegistrarAccount>
        rowKey="id"
        columns={columns}
        dataSource={accounts}
        loading={isLoading}
        rowSelection={{
          selectedRowKeys: selectedIds,
          onChange: (keys) => setSelectedIds(keys as number[]),
        }}
        pagination={{ showSizeChanger: true, pageSizeOptions: PAGE_SIZE_OPTIONS, showTotal: (count) => `${count} accounts` }}
        className="dms_registrars_table"
      />

      <RegistrarFormModal
        open={isFormOpen}
        account={editingAccount}
        supportedProviders={supportedProviders}
        onClose={() => setIsFormOpen(false)}
        onSaved={() => {
          setIsFormOpen(false);
          void load();
        }}
      />

      <Modal
        title={`Archive ${archivingAccount?.label ?? ""}?`}
        open={!!archivingAccount}
        onCancel={() => {
          setArchivingAccount(null);
          setArchiveReason("");
        }}
        onOk={handleArchive}
        okButtonProps={{ danger: true, disabled: !archiveReason.trim() }}
        confirmLoading={isArchiving}
        okText="Archive"
        className="dms_registrars_archive_modal"
      >
        <Typography.Paragraph type="secondary">
          Domains already purchased through it stay in inventory; this just removes the account from active use. A
          reason is required.
        </Typography.Paragraph>
        <Input.TextArea
          rows={3}
          value={archiveReason}
          onChange={(e) => setArchiveReason(e.target.value)}
          placeholder="Why is this account being archived?"
          className="dms_registrars_archive_reason_field"
        />
      </Modal>
    </div>
  );
}
