"use client";

import type { HealthStatus, ServerAccount, ServerGroup } from "@domainops/shared-types";
import { Alert, App, Button, Popconfirm, Table, Tag, Tooltip, Typography } from "antd";
import { DeleteOutlined, EditOutlined, PlusOutlined, SafetyOutlined, SyncOutlined } from "@ant-design/icons";
import type { ColumnsType } from "antd/es/table";
import { useCallback, useEffect, useState } from "react";
import {
  checkServerGroupHealth,
  deleteServerGroup,
  listServerAccounts,
  listServerGroups,
  syncServerAccounts,
} from "@/lib/api/servers";
import { ApiError } from "@/lib/api/client";
import { SORT_DIRECTIONS, textCompare } from "@/lib/utils/sort";
import { titleCase } from "@/lib/utils/text";
import { PAGE_SIZE_OPTIONS } from "@/lib/hooks/useServerPagination";
import { PageGuide } from "@/components/features/PageGuide";
import { SERVERS_GUIDES } from "@/lib/guides/servers";
import { AppIpBadge } from "./AppIpHint";
import { CapacityCell } from "./CapacityCell";
import { ServerGroupFormModal } from "./ServerGroupFormModal";
import { AddServerAccountModal } from "./AddServerAccountModal";
import { ServerAccountDrawer } from "./ServerAccountDrawer";
import { ServerSecurityGroupModal } from "./ServerSecurityGroupModal";

const HEALTH_COLORS: Record<HealthStatus, string> = {
  healthy: "green",
  degraded: "orange",
  unknown: "default",
};

function ServerAccountsPanel({ group }: { group: ServerGroup }) {
  const { message } = App.useApp();
  const [accounts, setAccounts] = useState<ServerAccount[]>([]);
  const [isAddAccountOpen, setIsAddAccountOpen] = useState(false);
  const [isSyncing, setIsSyncing] = useState(false);
  const [viewingAccountId, setViewingAccountId] = useState<number | null>(null);

  const load = useCallback(async () => {
    try {
      setAccounts(await listServerAccounts(group.id));
    } catch (err) {
      message.error(err instanceof ApiError ? err.message : "Couldn't load accounts.");
    }
  }, [group.id, message]);

  useEffect(() => {
    // Server data lives on the Laravel API, not in Next's own data layer -
    // a client fetch on mount, not a state-sync bug.
    // eslint-disable-next-line react-hooks/set-state-in-effect
    void load();
  }, [load]);

  async function handleSync() {
    setIsSyncing(true);
    try {
      const result = await syncServerAccounts(group.id);
      message.success(`Found ${result.accounts_found} account(s), added ${result.accounts_added} new.`);
      void load();
    } catch (err) {
      message.error(err instanceof ApiError ? err.message : "Couldn't sync accounts.");
    } finally {
      setIsSyncing(false);
    }
  }

  const columns: ColumnsType<ServerAccount> = [
    { title: "Username", dataIndex: "username", sorter: (a, b) => textCompare(a.username, b.username), sortDirections: SORT_DIRECTIONS, render: (v: string) => <span className="font-mono">{v}</span> },
    { title: "Workload", dataIndex: "workload_type", render: (v: string) => titleCase(v) },
    { title: "WP Toolkit", dataIndex: "wp_toolkit_available", render: (v: boolean) => (v ? "Yes" : "No") },
    { title: "Load", dataIndex: "current_load" },
  ];

  return (
    <div className="flex flex-col gap-3 py-2">
      <div className="flex justify-end gap-2">
        <Tooltip title="Pull every cPanel account already on this server via WHM">
          <Button size="small" icon={<SyncOutlined />} loading={isSyncing} onClick={handleSync} className="dms_servers_sync_accounts_btn">
            Sync Accounts
          </Button>
        </Tooltip>
        <Button size="small" icon={<PlusOutlined />} onClick={() => setIsAddAccountOpen(true)} className="dms_servers_add_account_btn">
          Add Account
        </Button>
      </div>
      <Table<ServerAccount>
        rowKey="id"
        size="small"
        columns={columns}
        dataSource={accounts}
        pagination={{ showSizeChanger: true, pageSizeOptions: PAGE_SIZE_OPTIONS, showTotal: (count) => `${count} accounts` }}
        onRow={(account) => ({ onClick: () => setViewingAccountId(account.id), style: { cursor: "pointer" } })}
        className="dms_servers_accounts_table"
      />
      <AddServerAccountModal
        open={isAddAccountOpen}
        serverGroupId={group.id}
        onClose={() => setIsAddAccountOpen(false)}
        onCreated={() => {
          setIsAddAccountOpen(false);
          void load();
        }}
      />
      <ServerAccountDrawer accountId={viewingAccountId} onClose={() => setViewingAccountId(null)} />
    </div>
  );
}

export default function ServersPage() {
  const { message, modal } = App.useApp();
  const [groups, setGroups] = useState<ServerGroup[]>([]);
  const [isLoading, setIsLoading] = useState(true);
  const [isFormOpen, setIsFormOpen] = useState(false);
  const [editingGroup, setEditingGroup] = useState<ServerGroup | null>(null);
  const [securityGroupTarget, setSecurityGroupTarget] = useState<ServerGroup | null>(null);
  const [checkingHealthId, setCheckingHealthId] = useState<number | null>(null);
  const [selectedIds, setSelectedIds] = useState<number[]>([]);
  const [isBulkWorking, setIsBulkWorking] = useState(false);

  const load = useCallback(async () => {
    setIsLoading(true);
    try {
      setGroups(await listServerGroups());
    } catch (err) {
      message.error(err instanceof ApiError ? err.message : "Couldn't load server groups.");
    } finally {
      setIsLoading(false);
    }
  }, [message]);

  useEffect(() => {
    // Server data lives on the Laravel API, not in Next's own data layer -
    // a client fetch on mount, not a state-sync bug.
    // eslint-disable-next-line react-hooks/set-state-in-effect
    void load();
  }, [load]);

  async function handleCheckHealth(group: ServerGroup) {
    setCheckingHealthId(group.id);
    try {
      const checked = await checkServerGroupHealth(group.id);
      const passed = (checked.health_detail ?? []).filter((check) => check.status === "ok").map((check) => check.message);
      message.success(`${group.label} is healthy. ${passed.join(" ")}`.trim(), 6);
    } catch (err) {
      message.error(err instanceof ApiError ? err.message : "Couldn't check that server.", 10);
    } finally {
      setCheckingHealthId(null);
      void load();
    }
  }

  function handleDelete(group: ServerGroup) {
    modal.confirm({
      title: `Delete ${group.label}?`,
      content: "Its cPanel accounts and any domains provisioned on them stay in inventory; this just removes the server group.",
      okButtonProps: { danger: true },
      onOk: async () => {
        try {
          await deleteServerGroup(group.id);
          message.success(`${group.label} deleted.`);
          void load();
        } catch (err) {
          message.error(err instanceof ApiError ? err.message : "Couldn't delete that server group.");
        }
      },
    });
  }

  const selectedGroups = groups.filter((g) => selectedIds.includes(g.id));

  async function runBulk(targets: ServerGroup[], action: (g: ServerGroup) => 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} group${succeeded === 1 ? "" : "s"}.`);
      if (failed > 0) message.error(`Failed for ${failed} group${failed === 1 ? "" : "s"}.`);
      setSelectedIds([]);
      void load();
    } finally {
      setIsBulkWorking(false);
    }
  }

  async function handleBulkCheckHealth() {
    await runBulk(selectedGroups, (g) => checkServerGroupHealth(g.id), "Checked");
  }

  async function handleBulkDelete() {
    await runBulk(selectedGroups, (g) => deleteServerGroup(g.id), "Deleted");
  }

  const fullGroups = groups.filter((group) => group.capacity?.state === "full");
  const nearGroups = groups.filter((group) => group.capacity?.state === "near");

  function capacityDetail(group: ServerGroup): string {
    const lines = [
      group.capacity?.static.limit ? `static ${group.capacity.static.used}/${group.capacity.static.limit}` : null,
      group.capacity?.wordpress.limit ? `WordPress ${group.capacity.wordpress.used}/${group.capacity.wordpress.limit}` : null,
    ].filter(Boolean);

    return lines.length > 0 ? ` (${lines.join(", ")})` : "";
  }

  const columns: ColumnsType<ServerGroup> = [
    { 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: "IP Address",
      dataIndex: "ip_address",
      render: (v: string | null) => (v ? <span className="font-mono">{v}</span> : "—"),
    },
    { title: "URL", dataIndex: "url", render: (v: string | null) => v ?? "—" },
    { title: "Connect Via", dataIndex: "auth_method", render: (v: string) => v.toUpperCase() },
    {
      title: "Health",
      dataIndex: "health_status",
      render: (v: HealthStatus, group) => (
        <Tooltip
          title={
            group.health_detail?.length ? (
              <div className="flex flex-col gap-1">
                {group.health_detail.map((check) => (
                  <span key={check.name}>
                    {check.status === "ok" ? "OK" : check.status === "failed" ? "Failed" : "Skipped"} - {check.name}: {check.message}
                  </span>
                ))}
              </div>
            ) : (
              "Not checked yet - use the sync button."
            )
          }
        >
          <Tag color={HEALTH_COLORS[v]}>{titleCase(v)}</Tag>
        </Tooltip>
      ),
    },
    {
      title: "Accounts",
      dataIndex: "accounts_count",
      render: (_: number | undefined, group) => <CapacityCell group={group} onSaved={() => void load()} />,
    },
    {
      title: "Actions",
      render: (_, group) => (
        <div className="flex gap-2">
          <Tooltip title="Check Health">
            <Button
              size="small"
              icon={<SyncOutlined />}
              loading={checkingHealthId === group.id}
              onClick={() => handleCheckHealth(group)}
              className="dms_servers_check_health_btn"
            />
          </Tooltip>
          {(group.connector_type === "aws" || group.connector_type === "huawei" || group.connector_type === "huawei_bt") && (
            <Tooltip title="Security Group">
              <Button
                size="small"
                icon={<SafetyOutlined />}
                onClick={() => setSecurityGroupTarget(group)}
                className="dms_servers_security_group_btn"
              />
            </Tooltip>
          )}
          <Tooltip title="Edit">
            <Button
              size="small"
              icon={<EditOutlined />}
              onClick={() => {
                setEditingGroup(group);
                setIsFormOpen(true);
              }}
              className="dms_servers_edit_group_btn"
            />
          </Tooltip>
          <Tooltip title="Delete">
            <Button
              size="small"
              danger
              icon={<DeleteOutlined />}
              onClick={() => handleDelete(group)}
              className="dms_servers_delete_group_btn"
            />
          </Tooltip>
        </div>
      ),
    },
  ];

  return (
    <div className="flex flex-col gap-4 page page-servers">
      <div className="flex items-center justify-between">
        <div className="flex items-center gap-2">
          <Typography.Title level={4} style={{ margin: 0 }}>
            Servers
          </Typography.Title>
          <PageGuide guides={SERVERS_GUIDES} label="Servers guide" />
          <AppIpBadge />
        </div>
        <Button
          type="primary"
          icon={<PlusOutlined />}
          onClick={() => {
            setEditingGroup(null);
            setIsFormOpen(true);
          }}
          className="dms_servers_add_group_btn"
        >
          Add Server Group
        </Button>
      </div>

      {fullGroups.length + nearGroups.length > 0 && (
        <Alert
          type={fullGroups.length > 0 ? "error" : "warning"}
          showIcon
          className="dms_servers_capacity_alert"
          title={fullGroups.length > 0 ? "Some servers are full" : "Some servers are nearly full"}
          description={[
            ...fullGroups.map((group) => `${group.label} is at its limit${capacityDetail(group)}.`),
            ...nearGroups.map((group) => `${group.label} is close to its limit${capacityDetail(group)}.`),
          ].join(" ")}
        />
      )}

      {selectedIds.length > 0 && (
        <div className="flex items-center gap-2 flex-wrap dms_servers_bulk_bar">
          <Typography.Text>{selectedIds.length} selected</Typography.Text>
          <Popconfirm title="Check health for the selected server groups?" onConfirm={handleBulkCheckHealth}>
            <Button size="small" icon={<SyncOutlined />} loading={isBulkWorking} className="dms_servers_bulk_check_health_btn">
              Check Health
            </Button>
          </Popconfirm>
          <Popconfirm title="Delete the selected server groups?" onConfirm={handleBulkDelete}>
            <Button size="small" danger icon={<DeleteOutlined />} loading={isBulkWorking} className="dms_servers_bulk_delete_btn">
              Delete
            </Button>
          </Popconfirm>
          <Button size="small" onClick={() => setSelectedIds([])} className="dms_servers_bulk_clear_btn">
            Clear
          </Button>
        </div>
      )}

      <Table<ServerGroup>
        rowKey="id"
        columns={columns}
        dataSource={groups}
        loading={isLoading}
        rowSelection={{
          selectedRowKeys: selectedIds,
          onChange: (keys) => setSelectedIds(keys as number[]),
        }}
        pagination={{ showSizeChanger: true, pageSizeOptions: PAGE_SIZE_OPTIONS, showTotal: (count) => `${count} server groups` }}
        expandable={{
          expandedRowRender: (group) => <ServerAccountsPanel group={group} />,
        }}
        className="dms_servers_table"
      />

      <ServerGroupFormModal
        open={isFormOpen}
        group={editingGroup}
        onClose={() => setIsFormOpen(false)}
        onSaved={() => {
          setIsFormOpen(false);
          void load();
        }}
      />

      <ServerSecurityGroupModal
        open={!!securityGroupTarget}
        group={securityGroupTarget}
        onClose={() => setSecurityGroupTarget(null)}
      />
    </div>
  );
}
