import {
  CopyOutlined,
  DeleteOutlined,
  DownloadOutlined,
  EditOutlined,
  EyeOutlined,
  PlayCircleOutlined,
  PlusOutlined,
  SettingOutlined,
} from '@ant-design/icons'
import {
  Button,
  Card,
  Collapse,
  Form,
  Input,
  Modal,
  Popconfirm,
  Select,
  Space,
  Table,
  Tag,
  Tooltip,
  Typography,
  message,
} from 'antd'
import type { ColumnsType } from 'antd/es/table'
import dayjs from 'dayjs'
import relativeTime from 'dayjs/plugin/relativeTime'
import 'dayjs/locale/ru'
import { useMemo, useState } from 'react'
import {
  useSnapshotDashboard,
  useSnapshotPolicies,
  useCreateSnapshotPolicy,
  useUpdateSnapshotPolicy,
  useDeleteSnapshotPolicy,
  useCollectPolicy,
  useCollectPolicyForObject,
  useDashboardDevices,
  fetchSnapshotContent,
  type SnapshotPolicy,
  type ObjectSnapshotSummary,
  type PolicySnapshotStatus,
  type DeviceSnapshotStatus,
} from '../api/snapshotPolicies'

dayjs.extend(relativeTime)
dayjs.locale('ru')

function copyToClipboard(text: string) {
  if (navigator.clipboard && window.isSecureContext) {
    navigator.clipboard.writeText(text)
  } else {
    const textarea = document.createElement('textarea')
    textarea.value = text
    textarea.style.position = 'fixed'
    textarea.style.left = '-9999px'
    document.body.appendChild(textarea)
    textarea.select()
    document.execCommand('copy')
    document.body.removeChild(textarea)
  }
}

const UNGROUPED = '__none__'

const CATEGORY_OPTIONS = [
  { value: 'main_server', label: 'Main Server' },
  { value: 'vm', label: 'VM' },
  { value: 'router', label: 'Router' },
  { value: 'embedded', label: 'Embedded' },
  { value: 'camera', label: 'Camera' },
  { value: 'io_board', label: 'IO Board' },
  { value: 'bank_terminal', label: 'Bank Terminal' },
  { value: 'cash_register', label: 'Cash Register' },
  { value: 'other', label: 'Other' },
]

const ACTION_OPTIONS = [
  { value: 'get_file', label: 'Get File (SSH)' },
  { value: 'mikrotik_get_config', label: 'MikroTik Get Config' },
]

interface PolicyFormValues {
  label: string
  category: string
  action_type: string
  path?: string
}

export function SnapshotDashboardPage() {
  const { data: dashboard, isLoading } = useSnapshotDashboard()
  const { data: policies } = useSnapshotPolicies()
  const [searchText, setSearchText] = useState('')
  const [policyModalOpen, setPolicyModalOpen] = useState(false)
  const [editPolicy, setEditPolicy] = useState<SnapshotPolicy | null>(null)
  const [settingsOpen, setSettingsOpen] = useState(false)
  const [form] = Form.useForm<PolicyFormValues>()
  const actionType = Form.useWatch('action_type', form)

  const createMutation = useCreateSnapshotPolicy()
  const updateMutation = useUpdateSnapshotPolicy()
  const deleteMutation = useDeleteSnapshotPolicy()
  const collectAllMutation = useCollectPolicy()
  const collectObjMutation = useCollectPolicyForObject()

  const filtered = useMemo(() => {
    if (!searchText || !dashboard) return dashboard ?? []
    const q = searchText.toLowerCase()
    return dashboard.filter(
      (o) =>
        o.object_name.toLowerCase().includes(q) ||
        (o.city ?? '').toLowerCase().includes(q) ||
        (o.client ?? '').toLowerCase().includes(q)
    )
  }, [dashboard, searchText])

  const cityGroups = useMemo(() => {
    const map = new Map<string, ObjectSnapshotSummary[]>()
    for (const obj of filtered) {
      const key = obj.city ?? UNGROUPED
      if (!map.has(key)) map.set(key, [])
      map.get(key)!.push(obj)
    }
    const sorted = [...map.entries()].sort(([a], [b]) => {
      if (a === UNGROUPED) return 1
      if (b === UNGROUPED) return -1
      return a.localeCompare(b, 'ru')
    })
    return sorted
  }, [filtered])

  const openCreatePolicy = () => {
    form.resetFields()
    setEditPolicy(null)
    setPolicyModalOpen(true)
  }

  const openEditPolicy = (policy: SnapshotPolicy) => {
    form.resetFields()
    form.setFieldsValue({
      label: policy.label,
      category: policy.category,
      action_type: policy.action_type,
      path: policy.action_type === 'get_file' ? (policy.params as any)?.path ?? '' : undefined,
    })
    setEditPolicy(policy)
    setPolicyModalOpen(true)
  }

  const handlePolicySubmit = async () => {
    const values = await form.validateFields()
    const params: Record<string, unknown> = {}
    if (values.action_type === 'get_file' && values.path) {
      params.path = values.path
    }

    try {
      if (editPolicy) {
        await updateMutation.mutateAsync({
          policyId: editPolicy.id,
          label: values.label,
          category: values.category,
          action_type: values.action_type,
          params,
        })
        message.success('Политика обновлена')
      } else {
        await createMutation.mutateAsync({
          label: values.label,
          category: values.category,
          action_type: values.action_type,
          params,
        })
        message.success('Политика создана')
      }
      setPolicyModalOpen(false)
    } catch {
      message.error('Ошибка при сохранении')
    }
  }

  const handleDeletePolicy = async (id: number) => {
    try {
      await deleteMutation.mutateAsync(id)
      message.success('Политика удалена')
    } catch {
      message.error('Ошибка при удалении')
    }
  }

  const handleCollectAll = async (policyId: number) => {
    try {
      const result = await collectAllMutation.mutateAsync(policyId)
      message.success(`Задача создана: ${result.task_id.slice(0, 8)}...`)
    } catch {
      message.error('Ошибка при запуске сбора')
    }
  }

  const handleCollectObj = async (policyId: number, objId: number) => {
    try {
      const result = await collectObjMutation.mutateAsync({ policyId, objId })
      message.success(`Задача создана: ${result.task_id.slice(0, 8)}...`)
    } catch {
      message.error('Ошибка при запуске сбора')
    }
  }

  // Policy settings columns
  const policyColumns: ColumnsType<SnapshotPolicy> = [
    { title: 'Название', dataIndex: 'label', key: 'label' },
    {
      title: 'Категория',
      dataIndex: 'category',
      key: 'category',
      render: (cat: string) => <Tag>{cat}</Tag>,
    },
    {
      title: 'Действие',
      dataIndex: 'action_type',
      key: 'action_type',
      render: (val: string, row) =>
        val === 'get_file' ? `Get File: ${(row.params as any)?.path ?? ''}` : 'MikroTik Export',
    },
    {
      title: '',
      key: 'actions',
      width: 160,
      render: (_, row) => (
        <Space size="small">
          <Tooltip title="Собрать со всех объектов">
            <Button
              type="text"
              size="small"
              icon={<PlayCircleOutlined />}
              onClick={() => handleCollectAll(row.id)}
            />
          </Tooltip>
          <Button type="text" size="small" icon={<EditOutlined />} onClick={() => openEditPolicy(row)} />
          <Popconfirm title="Удалить политику?" onConfirm={() => handleDeletePolicy(row.id)}>
            <Button type="text" size="small" danger icon={<DeleteOutlined />} />
          </Popconfirm>
        </Space>
      ),
    },
  ]

  return (
    <div>
      <div style={{ display: 'flex', justifyContent: 'space-between', marginBottom: 16 }}>
        <Typography.Title level={4} style={{ margin: 0 }}>
          Снапшоты
        </Typography.Title>
        <Space>
          <Input.Search
            placeholder="Поиск по объекту, городу..."
            allowClear
            style={{ width: 300 }}
            value={searchText}
            onChange={(e) => setSearchText(e.target.value)}
          />
          <Button icon={<SettingOutlined />} onClick={() => setSettingsOpen(!settingsOpen)}>
            Политики
          </Button>
        </Space>
      </div>

      {settingsOpen && (
        <Card size="small" style={{ marginBottom: 16 }} title="Глобальные политики сбора">
          <Table
            dataSource={policies ?? []}
            columns={policyColumns}
            rowKey="id"
            size="small"
            pagination={false}
          />
          <Button
            type="dashed"
            icon={<PlusOutlined />}
            onClick={openCreatePolicy}
            style={{ marginTop: 8, width: '100%' }}
          >
            Добавить политику
          </Button>
        </Card>
      )}

      {isLoading && <Typography.Text type="secondary">Загрузка...</Typography.Text>}

      {!isLoading && filtered.length === 0 && (
        <Typography.Text type="secondary">
          {(policies ?? []).length === 0
            ? 'Нет политик. Нажмите «Политики» чтобы настроить сбор снапшотов.'
            : 'Нет объектов с устройствами подходящих категорий.'}
        </Typography.Text>
      )}

      <Collapse
        defaultActiveKey={cityGroups.map(([city]) => city)}
        items={cityGroups.map(([city, objects]) => ({
          key: city,
          label: (
            <Space>
              <span>{city === UNGROUPED ? 'Без города' : city}</span>
              <Tag>{objects.length}</Tag>
            </Space>
          ),
          children: (
            <ObjectsTable
              objects={objects}
              onCollect={handleCollectObj}
            />
          ),
        }))}
      />

      <Modal
        title={editPolicy ? 'Редактировать политику' : 'Новая политика'}
        open={policyModalOpen}
        onCancel={() => setPolicyModalOpen(false)}
        onOk={handlePolicySubmit}
        confirmLoading={createMutation.isPending || updateMutation.isPending}
        okText="Сохранить"
        cancelText="Отмена"
      >
        <Form form={form} layout="vertical">
          <Form.Item name="label" label="Название" rules={[{ required: true, message: 'Введите название' }]}>
            <Input placeholder="CAPS config" />
          </Form.Item>
          <Form.Item name="category" label="Категория устройств" rules={[{ required: true }]}>
            <Select options={CATEGORY_OPTIONS} placeholder="Выберите категорию" />
          </Form.Item>
          <Form.Item name="action_type" label="Действие" rules={[{ required: true }]}>
            <Select options={ACTION_OPTIONS} placeholder="Выберите действие" />
          </Form.Item>
          {actionType === 'get_file' && (
            <Form.Item name="path" label="Путь к файлу" rules={[{ required: true, message: 'Укажите путь' }]}>
              <Input placeholder="/etc/caps/config.ini" />
            </Form.Item>
          )}
        </Form>
      </Modal>
    </div>
  )
}

function ObjectsTable({
  objects,
  onCollect,
}: {
  objects: ObjectSnapshotSummary[]
  onCollect: (policyId: number, objId: number) => void
}) {
  const [expandedKeys, setExpandedKeys] = useState<number[]>([])

  const columns: ColumnsType<ObjectSnapshotSummary> = [
    {
      title: 'Объект',
      key: 'name',
      render: (_, obj) => (
        <span>
          <Typography.Text strong>{obj.object_name}</Typography.Text>
          {obj.client && <Typography.Text type="secondary"> — {obj.client}</Typography.Text>}
        </span>
      ),
    },
    {
      title: 'Последний сбор',
      key: 'last_collected',
      width: 160,
      render: (_, obj) => {
        const latest = obj.policies.reduce<string | null>((acc, p) => {
          if (!p.last_collected_at) return acc
          if (!acc) return p.last_collected_at
          return p.last_collected_at > acc ? p.last_collected_at : acc
        }, null)
        return latest ? (
          <Tooltip title={dayjs(latest).format('DD.MM.YYYY HH:mm:ss')}>
            {dayjs(latest).fromNow()}
          </Tooltip>
        ) : (
          <Typography.Text type="secondary">—</Typography.Text>
        )
      },
    },
    {
      title: 'Покрытие',
      key: 'coverage',
      width: 120,
      render: (_, obj) => {
        const total = obj.policies.reduce((s, p) => s + p.total_devices, 0)
        const success = obj.policies.reduce((s, p) => s + p.success_count, 0)
        if (total === 0) return <Tag>нет устройств</Tag>
        const ratio = success / total
        const color = ratio >= 1 ? 'green' : ratio > 0 ? 'orange' : 'red'
        return (
          <Tag color={color}>
            {success} / {total}
          </Tag>
        )
      },
    },
    {
      title: '',
      key: 'actions',
      width: 50,
      render: (_, obj) => (
        <Tooltip title="Собрать все политики для объекта">
          <Button
            type="text"
            size="small"
            icon={<PlayCircleOutlined />}
            onClick={(e) => {
              e.stopPropagation()
              obj.policies.forEach((p) => onCollect(p.policy_id, obj.object_id))
            }}
          />
        </Tooltip>
      ),
    },
  ]

  return (
    <Table
      dataSource={objects}
      columns={columns}
      rowKey="object_id"
      size="small"
      pagination={false}
      onRow={(record) => ({
        onClick: () =>
          setExpandedKeys(
            expandedKeys.includes(record.object_id)
              ? expandedKeys.filter((k) => k !== record.object_id)
              : [...expandedKeys, record.object_id]
          ),
        style: { cursor: 'pointer' },
      })}
      expandable={{
        expandedRowKeys: expandedKeys,
        onExpand: (expanded, record) =>
          setExpandedKeys(
            expanded
              ? [...expandedKeys, record.object_id]
              : expandedKeys.filter((k) => k !== record.object_id)
          ),
        expandedRowRender: (record) => (
          <ObjectDevicesExpanded
            obj={record}
            onCollect={onCollect}
          />
        ),
      }}
    />
  )
}

function ObjectDevicesExpanded({
  obj,
  onCollect,
}: {
  obj: ObjectSnapshotSummary
  onCollect: (policyId: number, objId: number) => void
}) {
  if (obj.policies.length === 1) {
    return (
      <DevicesList
        objId={obj.object_id}
        objName={obj.object_name}
        policyId={obj.policies[0].policy_id}
      />
    )
  }

  return (
    <div>
      {obj.policies.map((p) => (
        <div key={p.policy_id} style={{ marginBottom: 12 }}>
          <div style={{ display: 'flex', alignItems: 'center', gap: 8, marginBottom: 4 }}>
            <Typography.Text strong>{p.policy_label}</Typography.Text>
            <Tag>{p.category}</Tag>
            <Tooltip title="Собрать">
              <Button
                type="text"
                size="small"
                icon={<PlayCircleOutlined />}
                onClick={() => onCollect(p.policy_id, obj.object_id)}
              />
            </Tooltip>
          </div>
          <DevicesList
            objId={obj.object_id}
            objName={obj.object_name}
            policyId={p.policy_id}
          />
        </div>
      ))}
    </div>
  )
}

function highlightIni(text: string): React.ReactNode[] {
  return text.split('\n').map((line, i) => {
    let node: React.ReactNode
    if (/^\s*[#;]/.test(line)) {
      node = <span style={{ color: '#6a9955' }}>{line}</span>
    } else if (/^\s*\[.+\]/.test(line) && !line.includes('=')) {
      node = <span style={{ color: '#ce9178', fontWeight: 600 }}>{line}</span>
    } else if (line.includes('=')) {
      const eqIdx = line.indexOf('=')
      const key = line.slice(0, eqIdx)
      const eq = '='
      const value = line.slice(eqIdx + 1)
      node = (
        <>
          <span style={{ color: '#9cdcfe' }}>{key}</span>
          <span style={{ color: '#d4d4d4' }}>{eq}</span>
          {highlightValue(value)}
        </>
      )
    } else {
      node = <span>{line}</span>
    }
    return <span key={i}>{node}{'\n'}</span>
  })
}

function highlightValue(value: string): React.ReactNode {
  const parts: React.ReactNode[] = []
  let i = 0
  let key = 0
  while (i < value.length) {
    const ch = value[i]
    if (ch === '"') {
      const end = value.indexOf('"', i + 1)
      if (end !== -1) {
        const str = value.slice(i, end + 1)
        parts.push(<span key={key++} style={{ color: '#dcdcaa' }}>{str}</span>)
        i = end + 1
      } else {
        parts.push(<span key={key++} style={{ color: '#dcdcaa' }}>{value.slice(i)}</span>)
        break
      }
    } else if (ch === '{' || ch === '}' || ch === '[' || ch === ']' || ch === ':' || ch === ',') {
      parts.push(<span key={key++} style={{ color: '#808080' }}>{ch}</span>)
      i++
    } else if (/\d/.test(ch)) {
      let num = ''
      while (i < value.length && /[\d.]/.test(value[i])) {
        num += value[i]
        i++
      }
      parts.push(<span key={key++} style={{ color: '#b5cea8' }}>{num}</span>)
    } else if (value.slice(i).startsWith('true') || value.slice(i).startsWith('false') || value.slice(i).startsWith('null')) {
      const word = value.slice(i).startsWith('true') ? 'true' : value.slice(i).startsWith('false') ? 'false' : 'null'
      parts.push(<span key={key++} style={{ color: '#569cd6' }}>{word}</span>)
      i += word.length
    } else {
      parts.push(<span key={key++} style={{ color: '#d4d4d4' }}>{ch}</span>)
      i++
    }
  }
  return <>{parts}</>
}

function DevicesList({
  objId,
  objName,
  policyId,
}: {
  objId: number
  objName: string
  policyId: number
}) {
  const { data: devices, isLoading } = useDashboardDevices(objId, policyId, true)
  const [viewContent, setViewContent] = useState<string | null>(null)
  const [viewTitle, setViewTitle] = useState('')

  const handleCopy = async (snapshotId: number) => {
    try {
      const content = await fetchSnapshotContent(snapshotId)
      copyToClipboard(content)
      message.success('Скопировано в буфер обмена')
    } catch {
      message.error('Ошибка при копировании')
    }
  }

  const handleDownload = async (device: DeviceSnapshotStatus) => {
    if (!device.snapshot_id) return
    try {
      const content = await fetchSnapshotContent(device.snapshot_id)
      const blob = new Blob([content], { type: 'text/plain;charset=utf-8' })
      const url = URL.createObjectURL(blob)
      const a = document.createElement('a')
      a.href = url
      a.download = `${objName}-${device.hostname || 'device'}-${device.ip}.txt`
      a.click()
      URL.revokeObjectURL(url)
    } catch {
      message.error('Ошибка при скачивании')
    }
  }

  const handleView = async (device: DeviceSnapshotStatus) => {
    if (!device.snapshot_id) return
    try {
      const content = await fetchSnapshotContent(device.snapshot_id)
      setViewTitle(`${device.hostname || device.ip} — ${objName}`)
      setViewContent(content)
    } catch {
      message.error('Ошибка при загрузке')
    }
  }

  const handleViewCopy = () => {
    if (viewContent) {
      copyToClipboard(viewContent)
      message.success('Скопировано в буфер обмена')
    }
  }

  if (isLoading) return <Typography.Text type="secondary">Загрузка...</Typography.Text>
  if (!devices || devices.length === 0) return <Typography.Text type="secondary">Нет устройств</Typography.Text>

  const columns: ColumnsType<DeviceSnapshotStatus> = [
    {
      title: 'IP',
      dataIndex: 'ip',
      key: 'ip',
      render: (ip: string) => <Typography.Text code>{ip}</Typography.Text>,
    },
    {
      title: 'Hostname',
      dataIndex: 'hostname',
      key: 'hostname',
      render: (val: string | null) => val || <Typography.Text type="secondary">—</Typography.Text>,
    },
    {
      title: 'Снапшот',
      key: 'status',
      render: (_, row) => {
        if (row.has_snapshot) return <Tag color="green">Есть</Tag>
        if (row.status === 'offline') return <Tag color="red">Нет пинга</Tag>
        return <Tag color="orange">Нет снапшота</Tag>
      },
    },
    {
      title: 'Собран',
      dataIndex: 'last_collected_at',
      key: 'last_collected_at',
      render: (val: string | null) =>
        val ? (
          <Tooltip title={dayjs(val).format('DD.MM.YYYY HH:mm:ss')}>
            {dayjs(val).fromNow()}
          </Tooltip>
        ) : (
          <Typography.Text type="secondary">—</Typography.Text>
        ),
    },
    {
      title: '',
      key: 'actions',
      width: 120,
      render: (_, row) =>
        row.snapshot_id ? (
          <Space size="small">
            <Tooltip title="Просмотр">
              <Button
                type="text"
                size="small"
                icon={<EyeOutlined />}
                onClick={() => handleView(row)}
              />
            </Tooltip>
            <Tooltip title="Скопировать">
              <Button
                type="text"
                size="small"
                icon={<CopyOutlined />}
                onClick={() => handleCopy(row.snapshot_id!)}
              />
            </Tooltip>
            <Tooltip title="Скачать">
              <Button
                type="text"
                size="small"
                icon={<DownloadOutlined />}
                onClick={() => handleDownload(row)}
              />
            </Tooltip>
          </Space>
        ) : null,
    },
  ]

  return (
    <>
      <Table
        dataSource={devices}
        columns={columns}
        rowKey="device_id"
        size="small"
        pagination={false}
      />
      <Modal
        title={
          <div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'center' }}>
            <span>{viewTitle}</span>
            <Button size="small" icon={<CopyOutlined />} onClick={handleViewCopy}>
              Скопировать
            </Button>
          </div>
        }
        open={viewContent !== null}
        onCancel={() => setViewContent(null)}
        footer={null}
        width={800}
        maskClosable
        destroyOnClose
      >
        <pre
          style={{
            background: '#1e1e1e',
            color: '#d4d4d4',
            padding: 16,
            borderRadius: 6,
            fontSize: 12,
            lineHeight: 1.5,
            maxHeight: '70vh',
            overflow: 'auto',
            whiteSpace: 'pre-wrap',
            wordBreak: 'break-all',
            margin: 0,
            fontFamily: "'Consolas', 'Monaco', 'Courier New', monospace",
          }}
        >
          {viewContent && highlightIni(viewContent)}
        </pre>
      </Modal>
    </>
  )
}
