import { useState } from 'react'
import { Alert, Button, Drawer, Form, Input, InputNumber, Modal, Select, Space, Switch, Tabs, Tag, Typography, message } from 'antd'
import type { ColumnsType } from 'antd/es/table'
import { GlobalOutlined, NodeIndexOutlined, PlusOutlined, SettingOutlined } from '@ant-design/icons'
import { useMutation, useQuery, useQueryClient } from '@tanstack/react-query'
import { useTranslation } from 'react-i18next'

import apiClient, { isEnvelope } from '../../api/client'
import DataTable from '../../components/DataTable'
import PageHeader from '../../components/PageHeader'
import ActionButtons from '../../components/ActionButtons'
import StatusDot from '../../components/StatusDot'

const { Text } = Typography

interface Zone {
  id: number
  name: string
  zone_type: 'local' | 'forward'
  description?: string | null
  managed_by: string
  forward_to?: string | null
  active: boolean
}

interface DNSRecord {
  id: number
  zone_id: number
  name: string
  record_type: string
  value: string
  ttl: number
  active: boolean
}

interface Settings {
  listen_addresses: string
  listen_port: number
  upstream_forwards: string
  access_acl: string
  dnssec: boolean
  qname_minimisation: boolean
  cache_min_ttl: number
  cache_max_ttl: number
}

const RECORD_TYPES = ['A', 'AAAA', 'CNAME', 'TXT', 'MX', 'SRV', 'NS', 'PTR', 'CAA']

async function listZones(): Promise<Zone[]> {
  const r = await apiClient.get('/dns/zones')
  if (!isEnvelope(r.data)) return []
  return (r.data.data as { zones?: Zone[] }).zones ?? []
}
async function listRecords(zoneID: number): Promise<DNSRecord[]> {
  const r = await apiClient.get(`/dns/zones/${zoneID}/records`)
  if (!isEnvelope(r.data)) return []
  return (r.data.data as { records?: DNSRecord[] }).records ?? []
}
async function getSettings(): Promise<Settings | null> {
  const r = await apiClient.get('/dns/settings')
  return isEnvelope(r.data) ? (r.data.data as Settings) : null
}

interface SystemIface {
  ifname: string
  addr_info?: Array<{ family: 'inet' | 'inet6'; local: string; prefixlen: number }>
}
async function listSystemInterfaces(): Promise<SystemIface[]> {
  const r = await apiClient.get('/system/interfaces')
  if (!isEnvelope(r.data)) return []
  return (r.data.data as { interfaces?: SystemIface[] }).interfaces ?? []
}

export default function DNSPage() {
  const { t } = useTranslation()
  return (
    <div>
      <PageHeader
        icon={<GlobalOutlined />}
        title={t('dns.title')}
        subtitle={t('dns.intro')}
      />
      <Tabs
        defaultActiveKey="zones"
        items={[
          { key: 'zones',    label: <span><NodeIndexOutlined /> {t('dns.tabs.zones')}</span>,    children: <ZonesTab /> },
          { key: 'settings', label: <span><SettingOutlined /> {t('dns.tabs.settings')}</span>,  children: <SettingsTab /> },
        ]}
      />
    </div>
  )
}

// ── Zones tab ──────────────────────────────────────────────────

function ZonesTab() {
  const { t } = useTranslation()
  const qc = useQueryClient()
  const { data, isLoading } = useQuery({ queryKey: ['dns', 'zones'], queryFn: listZones })

  const [editing, setEditing] = useState<Zone | null>(null)
  const [creating, setCreating] = useState(false)
  const [form] = Form.useForm<Zone>()

  const [recordsZone, setRecordsZone] = useState<Zone | null>(null)

  const upsert = useMutation({
    mutationFn: async (v: Zone) => {
      if (editing) return (await apiClient.put(`/dns/zones/${editing.id}`, v)).data
      return (await apiClient.post('/dns/zones', v)).data
    },
    onSuccess: () => {
      message.success(t('common.save'))
      setEditing(null); setCreating(false); form.resetFields()
      void qc.invalidateQueries({ queryKey: ['dns', 'zones'] })
    },
    onError: (e: Error) => message.error(e.message),
  })
  const del = useMutation({
    mutationFn: async (id: number) => { await apiClient.delete(`/dns/zones/${id}`) },
    onSuccess: () => { void qc.invalidateQueries({ queryKey: ['dns', 'zones'] }) },
    onError: (e: Error) => message.error(e.message),
  })

  const cols: ColumnsType<Zone> = [
    { title: t('dns.zone.name'), dataIndex: 'name', key: 'name', render: (s: string) => <code>{s}</code> },
    { title: t('dns.zone.type'), dataIndex: 'zone_type', key: 'zone_type',
      render: (s: string) => <Tag color={s === 'local' ? 'blue' : 'purple'}>{s}</Tag> },
    { title: t('dns.zone.forwardTo'), dataIndex: 'forward_to', key: 'forward_to',
      render: (v?: string | null) => v ? <Text code style={{ fontSize: 11 }}>{v}</Text> : '—' },
    { title: t('dns.zone.description'), dataIndex: 'description', key: 'description', render: (v?: string | null) => v ?? '—' },
    { title: t('common.active'), dataIndex: 'active', key: 'active', render: (v: boolean) => <StatusDot active={v} /> },
    {
      title: t('common.actions'), key: 'actions',
      render: (_, row) => (
        <Space size={4}>
          {row.zone_type === 'local' && (
            <Button size="small" type="text" onClick={() => setRecordsZone(row)}>
              {t('dns.zone.records')}
            </Button>
          )}
          <ActionButtons
            onEdit={() => {
              setEditing(row)
              form.setFieldsValue(row)
            }}
            onDelete={() => del.mutate(row.id)}
            deleteConfirm={t('dns.zone.deleteConfirm', { name: row.name })}
          />
        </Space>
      ),
    },
  ]

  return (
    <>
      <DataTable
        rowKey="id"
        loading={isLoading}
        dataSource={data ?? []}
        columns={cols}
        extraActions={
          <Button type="primary" icon={<PlusOutlined />} onClick={() => {
            setCreating(true); form.resetFields()
            form.setFieldsValue({ zone_type: 'local', active: true } as Zone)
          }}>
            {t('dns.zone.add')}
          </Button>
        }
      />

      <Modal
        title={editing ? t('dns.zone.edit') : t('dns.zone.add')}
        open={editing !== null || creating}
        onCancel={() => { setEditing(null); setCreating(false); form.resetFields() }}
        onOk={() => { void form.submit() }}
        confirmLoading={upsert.isPending}
        width={580}
        destroyOnClose
      >
        <Form form={form} layout="vertical" onFinish={(v) => upsert.mutate(v)}>
          <Form.Item label={t('dns.zone.name')} name="name" rules={[{ required: true }]}
                     extra={t('dns.zone.nameExtra')}>
            <Input placeholder="internal.netcell-it.de" />
          </Form.Item>
          <Form.Item label={t('dns.zone.type')} name="zone_type" rules={[{ required: true }]}>
            <Select options={[
              { value: 'local',   label: t('dns.zone.typeLocal') },
              { value: 'forward', label: t('dns.zone.typeForward') },
            ]} />
          </Form.Item>
          <Form.Item noStyle shouldUpdate={(p, c) => p.zone_type !== c.zone_type}>
            {({ getFieldValue }) => getFieldValue('zone_type') === 'forward' && (
              <Form.Item label={t('dns.zone.forwardTo')} name="forward_to" rules={[{ required: true }]}
                         extra={t('dns.zone.forwardToExtra')}>
                <Input placeholder="10.0.0.53, 8.8.8.8" />
              </Form.Item>
            )}
          </Form.Item>
          <Form.Item label={t('dns.zone.description')} name="description">
            <Input.TextArea rows={2} />
          </Form.Item>
          <Form.Item label={t('common.active')} name="active" valuePropName="checked">
            <Switch />
          </Form.Item>
        </Form>
      </Modal>

      <RecordsDrawer zone={recordsZone} onClose={() => setRecordsZone(null)} />
    </>
  )
}

// ── Records drawer ────────────────────────────────────────────

interface RecordsDrawerProps {
  zone: Zone | null
  onClose: () => void
}

function RecordsDrawer({ zone, onClose }: RecordsDrawerProps) {
  const { t } = useTranslation()
  const qc = useQueryClient()
  const open = zone !== null
  const zoneID = zone?.id ?? 0

  const { data, isLoading } = useQuery({
    queryKey: ['dns', 'records', zoneID],
    queryFn: () => listRecords(zoneID),
    enabled: open,
  })

  const [editing, setEditing] = useState<DNSRecord | null>(null)
  const [creating, setCreating] = useState(false)
  const [form] = Form.useForm<DNSRecord>()

  const upsert = useMutation({
    mutationFn: async (v: DNSRecord) => {
      if (editing) return (await apiClient.put(`/dns/records/${editing.id}`, v)).data
      return (await apiClient.post(`/dns/zones/${zoneID}/records`, v)).data
    },
    onSuccess: () => {
      message.success(t('common.save'))
      setEditing(null); setCreating(false); form.resetFields()
      void qc.invalidateQueries({ queryKey: ['dns', 'records', zoneID] })
    },
    onError: (e: Error) => message.error(e.message),
  })
  const del = useMutation({
    mutationFn: async (id: number) => { await apiClient.delete(`/dns/records/${id}`) },
    onSuccess: () => { void qc.invalidateQueries({ queryKey: ['dns', 'records', zoneID] }) },
    onError: (e: Error) => message.error(e.message),
  })

  const cols: ColumnsType<DNSRecord> = [
    { title: t('dns.record.name'), dataIndex: 'name', key: 'name', render: (s: string) => <code>{s}</code> },
    { title: t('dns.record.type'), dataIndex: 'record_type', key: 'record_type', render: (s: string) => <Tag>{s}</Tag> },
    { title: t('dns.record.value'), dataIndex: 'value', key: 'value', render: (s: string) => <Text code style={{ fontSize: 12 }}>{s}</Text> },
    { title: t('dns.record.ttl'), dataIndex: 'ttl', key: 'ttl', width: 80 },
    { title: t('common.active'), dataIndex: 'active', key: 'active', render: (v: boolean) => <StatusDot active={v} /> },
    {
      title: t('common.actions'), key: 'actions',
      render: (_, row) => (
        <ActionButtons
          onEdit={() => {
            setEditing(row)
            form.setFieldsValue(row)
          }}
          onDelete={() => del.mutate(row.id)}
          deleteConfirm={t('dns.record.deleteConfirm', { name: row.name })}
        />
      ),
    },
  ]

  return (
    <Drawer
      open={open}
      onClose={onClose}
      width={920}
      title={zone && (
        <Space>
          <span>{t('dns.record.drawerTitle')}</span>
          <Tag color="blue"><code>{zone.name}</code></Tag>
        </Space>
      )}
      destroyOnClose
    >
      <DataTable
        rowKey="id"
        loading={isLoading}
        dataSource={data ?? []}
        columns={cols}
        extraActions={
          <Button type="primary" icon={<PlusOutlined />} onClick={() => {
            setCreating(true); form.resetFields()
            form.setFieldsValue({ record_type: 'A', ttl: 300, active: true } as DNSRecord)
          }}>
            {t('dns.record.add')}
          </Button>
        }
      />

      <Modal
        title={editing ? t('dns.record.edit') : t('dns.record.add')}
        open={editing !== null || creating}
        onCancel={() => { setEditing(null); setCreating(false); form.resetFields() }}
        onOk={() => { void form.submit() }}
        confirmLoading={upsert.isPending}
        width={580}
        destroyOnClose
      >
        <Form form={form} layout="vertical" onFinish={(v) => upsert.mutate(v)}>
          <Form.Item label={t('dns.record.name')} name="name" rules={[{ required: true }]}
                     extra={t('dns.record.nameExtra')}>
            <Input placeholder="mailcow oder mailcow.internal.netcell-it.de." />
          </Form.Item>
          <Form.Item label={t('dns.record.type')} name="record_type" rules={[{ required: true }]}>
            <Select options={RECORD_TYPES.map(r => ({ value: r, label: r }))} />
          </Form.Item>
          <Form.Item label={t('dns.record.value')} name="value" rules={[{ required: true }]}
                     extra={t('dns.record.valueExtra')}>
            <Input placeholder="10.10.20.5" />
          </Form.Item>
          <Form.Item label={t('dns.record.ttl')} name="ttl">
            <InputNumber min={30} max={86400} style={{ width: '100%' }} />
          </Form.Item>
          <Form.Item label={t('common.active')} name="active" valuePropName="checked">
            <Switch />
          </Form.Item>
        </Form>
      </Modal>
    </Drawer>
  )
}

// ── Settings tab ──────────────────────────────────────────────

// Settings-Form-Shape unterscheidet sich vom Wire-Shape: listen_addresses
// ist im UI ein Array (Multi-Select), wird beim Save zur Komma-CSV.
interface SettingsForm extends Omit<Settings, 'listen_addresses'> {
  listen_addresses: string[]
}

function SettingsTab() {
  const { t } = useTranslation()
  const qc = useQueryClient()
  const { data, isLoading } = useQuery({ queryKey: ['dns', 'settings'], queryFn: getSettings })
  const { data: sys } = useQuery({ queryKey: ['system', 'interfaces'], queryFn: listSystemInterfaces })
  const [form] = Form.useForm<SettingsForm>()

  // Multi-Select-Optionen: alle IPv4/IPv6 die der Kernel kennt + Spezial-
  // Werte (0.0.0.0 = alle IPv4, :: = alle IPv6, 127.0.0.1 / ::1 = lo).
  // Mode "tags" damit der Operator notfalls auch eine IP eintippen kann
  // die der Kernel noch nicht meldet (z.B. eine geplante VIP).
  const ipOptions: { value: string; label: string }[] = []
  ipOptions.push({ value: '0.0.0.0', label: '0.0.0.0 — alle IPv4-Interfaces' })
  ipOptions.push({ value: '::',      label: ':: — alle IPv6-Interfaces' })
  ipOptions.push({ value: '127.0.0.1', label: '127.0.0.1 — Loopback IPv4' })
  ipOptions.push({ value: '::1',       label: '::1 — Loopback IPv6' })
  for (const i of sys ?? []) {
    if (i.ifname === 'lo') continue
    for (const a of i.addr_info ?? []) {
      ipOptions.push({
        value: a.local,
        label: `${a.local} — ${i.ifname} (${a.family === 'inet' ? 'IPv4' : 'IPv6'})`,
      })
    }
  }

  const initial: SettingsForm | undefined = data ? {
    ...data,
    listen_addresses: data.listen_addresses
      .split(',')
      .map(s => s.trim())
      .filter(Boolean),
  } : undefined

  const save = useMutation({
    mutationFn: async (v: SettingsForm) => {
      const body: Settings = { ...v, listen_addresses: v.listen_addresses.join(', ') }
      return (await apiClient.put('/dns/settings', body)).data
    },
    onSuccess: () => {
      message.success(t('common.save'))
      void qc.invalidateQueries({ queryKey: ['dns', 'settings'] })
    },
    onError: (e: Error) => message.error(e.message),
  })

  if (isLoading) return null
  return (
    <Form
      form={form}
      layout="vertical"
      initialValues={initial}
      onFinish={(v) => save.mutate(v)}
      style={{ maxWidth: 720 }}
    >
      <Alert type="info" showIcon className="mb-12" message={t('dns.settings.intro')} />
      <Form.Item
        label={t('dns.settings.listenAddresses')}
        name="listen_addresses"
        rules={[{ required: true, type: 'array', min: 1, message: t('dns.settings.listenAddressesRequired') }]}
        extra={t('dns.settings.listenAddressesExtra')}
      >
        <Select
          mode="tags"
          placeholder={t('dns.settings.listenAddressesPlaceholder')}
          options={ipOptions}
          showSearch
          optionFilterProp="value"
        />
      </Form.Item>
      <Form.Item label={t('dns.settings.listenPort')} name="listen_port" rules={[{ required: true }]}>
        <InputNumber min={1} max={65535} style={{ width: '100%' }} />
      </Form.Item>
      <Form.Item label={t('dns.settings.upstreamForwards')} name="upstream_forwards" rules={[{ required: true }]}
                 extra={t('dns.settings.upstreamForwardsExtra')}>
        <Input placeholder="1.1.1.1, 9.9.9.9" />
      </Form.Item>
      <Form.Item label={t('dns.settings.accessACL')} name="access_acl" rules={[{ required: true }]}
                 extra={t('dns.settings.accessACLExtra')}>
        <Input placeholder="127.0.0.0/8, 10.0.0.0/8" />
      </Form.Item>
      <Form.Item label={t('dns.settings.dnssec')} name="dnssec" valuePropName="checked">
        <Switch />
      </Form.Item>
      <Form.Item label={t('dns.settings.qnameMin')} name="qname_minimisation" valuePropName="checked">
        <Switch />
      </Form.Item>
      <Space>
        <Form.Item label={t('dns.settings.cacheMin')} name="cache_min_ttl">
          <InputNumber min={0} style={{ width: 120 }} />
        </Form.Item>
        <Form.Item label={t('dns.settings.cacheMax')} name="cache_max_ttl">
          <InputNumber min={60} style={{ width: 120 }} />
        </Form.Item>
      </Space>
      <Form.Item>
        <Button type="primary" htmlType="submit" loading={save.isPending}>
          {t('common.save')}
        </Button>
      </Form.Item>
    </Form>
  )
}
