import { useCallback, useEffect, useState } from "react"
import { Plus, RefreshCw, Trash2 } from "lucide-react"

import { useArcadiaClient } from "@crema/arcadia-core-client"
import { useToast } from "@crema/notification-ui"
import { ConfirmDialog, EmptyState } from "@crema/feedback-ui"
import { BadgeCell } from "@crema/table-ui"

import type { TenantTabProps } from "~/routes/tenants.$id"
import { DataState, DialogError } from "~/components/data-state"
import { errorMessage } from "~/lib/errors"
import { Button } from "~/components/ui/button"
import {
  Card,
  CardContent,
  CardDescription,
  CardHeader,
  CardTitle,
} from "~/components/ui/card"
import {
  Dialog,
  DialogContent,
  DialogDescription,
  DialogFooter,
  DialogHeader,
  DialogTitle,
} from "~/components/ui/dialog"
import { Input } from "~/components/ui/input"
import { Label } from "~/components/ui/label"
import { NativeSelect, NativeSelectOption } from "~/components/ui/native-select"
import { Switch } from "~/components/ui/switch"
import {
  createIpRule,
  deleteIpRule,
  listIpRules,
  updateIpRule,
  type IpRule,
} from "~/lib/arcadia/tenants"

/**
 * Per-tenant IP allow/deny rules. With no allow rules every IP is permitted;
 * an allow rule locks access to known ranges, a deny rule blocks specific ones.
 */
export function IpRulesTab({ tenant }: TenantTabProps) {
  const arcadia = useArcadiaClient()
  const toast = useToast()

  const [rules, setRules] = useState<IpRule[]>([])
  const [loading, setLoading] = useState(true)
  // Raw thrown value; DataState normalises it. A failed load must never render
  // as "no rules — every IP allowed".
  const [error, setError] = useState<unknown>(null)
  const [busy, setBusy] = useState<Set<string>>(new Set())
  const [addOpen, setAddOpen] = useState(false)
  const [pendingDelete, setPendingDelete] = useState<IpRule | null>(null)

  const load = useCallback(async () => {
    setError(null)
    setLoading(true)
    try {
      setRules(await listIpRules(arcadia, tenant.id))
    } catch (err) {
      setError(err)
    } finally {
      setLoading(false)
    }
  }, [arcadia, tenant.id])

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

  const markBusy = (id: string, on: boolean) =>
    setBusy((prev) => {
      const next = new Set(prev)
      if (on) next.add(id)
      else next.delete(id)
      return next
    })

  const toggle = useCallback(
    async (rule: IpRule, next: boolean) => {
      markBusy(rule.id, true)
      setRules((prev) =>
        prev.map((r) => (r.id === rule.id ? { ...r, enabled: next } : r)),
      )
      try {
        const updated = await updateIpRule(arcadia, tenant.id, rule.id, {
          enabled: next,
        })
        setRules((prev) => prev.map((r) => (r.id === updated.id ? updated : r)))
        toast.success(
          `${next ? "Enabled" : "Disabled"} ${rule.rule_type} rule ${rule.cidr}`,
        )
      } catch (err) {
        setRules((prev) =>
          prev.map((r) => (r.id === rule.id ? { ...r, enabled: !next } : r)),
        )
        toast.error(errorMessage(err, `update rule ${rule.cidr}`))
      } finally {
        markBusy(rule.id, false)
      }
    },
    [arcadia, tenant.id, toast],
  )

  return (
    <Card>
      <CardHeader className="flex flex-row items-start justify-between gap-4">
        <div className="space-y-1">
          <CardTitle>IP rules</CardTitle>
          <CardDescription>
            Control which client IPs may reach {tenant.name}. With no allow
            rules, every IP is allowed.
          </CardDescription>
        </div>
        <div className="flex items-center gap-2">
          <Button
            variant="outline"
            size="sm"
            onClick={load}
            disabled={loading}
            data-action="tenant-detail-ip-refresh"
          >
            <RefreshCw className={`size-4 ${loading ? "animate-spin" : ""}`} />
            Refresh
          </Button>
          <Button
            size="sm"
            onClick={() => setAddOpen(true)}
            data-action="tenant-detail-ip-add"
          >
            <Plus className="size-4" />
            Add rule
          </Button>
        </div>
      </CardHeader>

      <CardContent className="relative p-0">
        <DataState
          loading={loading}
          error={error}
          isEmpty={rules.length === 0}
          onRetry={load}
          loadingLabel="Loading IP rules…"
          empty={
            <EmptyState
              title="No IP rules."
              description="With no allow rules, every IP is allowed; add a deny rule to block specific ranges, or an allow rule to lock access down to known ranges."
              className="py-12"
            />
          }
        >
          <div className="overflow-x-auto">
            <table className="w-full text-sm">
              <thead>
                <tr className="border-b text-left text-xs uppercase tracking-wider text-muted-foreground">
                  <th className="px-6 py-2 font-medium">CIDR</th>
                  <th className="px-4 py-2 font-medium">Type</th>
                  <th className="px-4 py-2 font-medium">Description</th>
                  <th className="px-4 py-2 font-medium">Enabled</th>
                  <th className="px-6 py-2" />
                </tr>
              </thead>
              <tbody className="divide-y">
                {rules.map((rule) => {
                  const isBusy = busy.has(rule.id)
                  return (
                    <tr key={rule.id}>
                      <td className="px-6 py-3">
                        <code className="font-mono text-xs">{rule.cidr}</code>
                      </td>
                      <td className="px-4 py-3">
                        <BadgeCell
                          label={rule.rule_type}
                          tone={rule.rule_type === "deny" ? "danger" : "success"}
                        />
                      </td>
                      <td className="px-4 py-3 text-muted-foreground">
                        {rule.description || "—"}
                      </td>
                      <td className="px-4 py-3">
                        <Switch
                          checked={rule.enabled}
                          disabled={isBusy}
                          onCheckedChange={(next) => toggle(rule, next)}
                          data-action={`tenant-detail-ip-toggle-${rule.id}`}
                        />
                      </td>
                      <td className="px-6 py-3 text-right">
                        <Button
                          variant="ghost"
                          size="icon-sm"
                          className="text-destructive"
                          disabled={isBusy}
                          onClick={() => setPendingDelete(rule)}
                          aria-label={`Delete rule ${rule.cidr}`}
                          data-action={`tenant-detail-ip-delete-${rule.id}`}
                        >
                          <Trash2 className="size-4" />
                        </Button>
                      </td>
                    </tr>
                  )
                })}
              </tbody>
            </table>
          </div>
        </DataState>
      </CardContent>

      <AddIpRuleDialog
        open={addOpen}
        tenantId={tenant.id}
        onClose={() => setAddOpen(false)}
        onSaved={async (msg) => {
          setAddOpen(false)
          await load()
          toast.success(msg)
        }}
      />

      <ConfirmDialog
        open={pendingDelete !== null}
        onOpenChange={(o) => !o && setPendingDelete(null)}
        title="Delete IP rule?"
        description={
          pendingDelete
            ? `The ${pendingDelete.rule_type} rule for ${pendingDelete.cidr} will be removed. If this was the last allow rule, every IP becomes allowed again.`
            : ""
        }
        confirmLabel="Delete"
        variant="danger"
        onConfirm={async () => {
          if (!pendingDelete) return
          const target = pendingDelete
          try {
            await deleteIpRule(arcadia, tenant.id, target.id)
            setPendingDelete(null)
            await load()
            toast.success(`Deleted ${target.rule_type} rule ${target.cidr}`)
          } catch (err) {
            setPendingDelete(null)
            toast.error(errorMessage(err, `delete rule ${target.cidr}`))
          }
        }}
      />
    </Card>
  )
}

function AddIpRuleDialog({
  open,
  tenantId,
  onClose,
  onSaved,
}: {
  open: boolean
  tenantId: string
  onClose: () => void
  onSaved: (message: string) => Promise<void>
}) {
  const arcadia = useArcadiaClient()
  const [cidr, setCidr] = useState("")
  const [ruleType, setRuleType] = useState<"allow" | "deny">("allow")
  const [description, setDescription] = useState("")
  const [enabled, setEnabled] = useState(true)
  const [saving, setSaving] = useState(false)
  // Failed submit renders here, above the buttons, form kept intact.
  const [error, setError] = useState<unknown>(null)

  useEffect(() => {
    if (!open) return
    setCidr("")
    setRuleType("allow")
    setDescription("")
    setEnabled(true)
    setError(null)
  }, [open])

  const submit = async () => {
    const trimmed = cidr.trim()
    setError(null)
    setSaving(true)
    try {
      if (!trimmed) throw new Error("A CIDR range is required.")
      await createIpRule(arcadia, tenantId, {
        cidr: trimmed,
        rule_type: ruleType,
        description: description.trim() || undefined,
        enabled,
      })
      await onSaved(`Added ${ruleType} rule ${trimmed}`)
    } catch (err) {
      setError(err)
    } finally {
      setSaving(false)
    }
  }

  return (
    <Dialog open={open} onOpenChange={(o) => !o && onClose()}>
      <DialogContent className="sm:max-w-md">
        <DialogHeader>
          <DialogTitle>Add IP rule</DialogTitle>
          <DialogDescription>
            Allow rules lock access to known ranges; deny rules block specific
            ones.
          </DialogDescription>
        </DialogHeader>

        <div className="flex flex-col gap-4">
          <div className="flex flex-col gap-1.5">
            <Label htmlFor="ip-cidr">CIDR range</Label>
            <Input
              id="ip-cidr"
              value={cidr}
              onChange={(e) => setCidr(e.target.value)}
              placeholder="203.0.113.0/24"
              className="font-mono"
              autoFocus
              data-action="tenant-detail-ip-form-cidr"
            />
          </div>

          <div className="flex flex-col gap-1.5">
            <Label htmlFor="ip-type">Rule type</Label>
            <NativeSelect
              id="ip-type"
              className="w-full"
              value={ruleType}
              onChange={(e) => setRuleType(e.target.value as "allow" | "deny")}
              data-action="tenant-detail-ip-form-type"
            >
              <NativeSelectOption value="allow">Allow</NativeSelectOption>
              <NativeSelectOption value="deny">Deny</NativeSelectOption>
            </NativeSelect>
          </div>

          <div className="flex flex-col gap-1.5">
            <Label htmlFor="ip-description">Description</Label>
            <Input
              id="ip-description"
              value={description}
              onChange={(e) => setDescription(e.target.value)}
              placeholder="Office VPN egress"
              data-action="tenant-detail-ip-form-description"
            />
          </div>

          <div className="flex items-center justify-between rounded-md border px-3 py-2">
            <div>
              <div className="text-sm font-medium">Enabled</div>
              <div className="text-xs text-muted-foreground">
                Disabled rules are kept but not enforced.
              </div>
            </div>
            <Switch
              checked={enabled}
              onCheckedChange={setEnabled}
              data-action="tenant-detail-ip-form-enabled"
            />
          </div>
        </div>

        {error ? <DialogError error={error} context="add the rule" /> : null}

        <DialogFooter>
          <Button
            variant="outline"
            onClick={onClose}
            disabled={saving}
            data-action="tenant-detail-ip-form-cancel"
          >
            Cancel
          </Button>
          <Button
            onClick={submit}
            disabled={saving || !cidr.trim()}
            data-action="tenant-detail-ip-form-save"
          >
            {saving ? <RefreshCw className="size-4 animate-spin" /> : null}
            Add rule
          </Button>
        </DialogFooter>
      </DialogContent>
    </Dialog>
  )
}
