import { ArrowLeftOutlined } from '@ant-design/icons'
import { useQueryClient } from '@tanstack/react-query'
import { Alert, Button, Card, Col, Collapse, Empty, Row, Select, Space, Table, Tag, Typography } from 'antd'
import type { ColumnsType } from 'antd/es/table'
import dayjs from 'dayjs'
import { useMemo, useState } from 'react'
import { useNavigate, useParams, useSearchParams } from 'react-router-dom'
import {
  useDashboardObjectAvailability,
  useDashboardObjectDevices,
  useDashboardObjectSummary,
  type DashboardAvailabilityPoint,
  type DashboardAvailabilityWindow,
  type DashboardDeviceNOCItem,
  type DashboardScope,
} from '../api/dashboard'
import { useDashboardMonitorSSE } from '../hooks/useDashboardMonitorSSE'

function reasonLabel(reason: string): string {
  const map: Record<string, string> = {
    object_include_policy: 'Включен политикой объекта',
    object_exclude_policy: 'Исключен политикой объекта',
    inherit_default: 'Наследование по умолчанию',
    tag_policy_enabled: 'Включен политикой тегов',
    tag_policy_disabled: 'Исключен политикой тегов',
    scope_filtered: 'Вне текущего фильтра',
  }
  return map[reason] ?? reason
}

function parseScope(params: URLSearchParams): DashboardScope {
  const city = params.get('city') ?? undefined
  const client = params.get('client') ?? undefined
  const object_ids = params.getAll('object_ids').map(Number).filter((v) => Number.isFinite(v))
  const tag_ids = params.getAll('tag_ids').map(Number).filter((v) => Number.isFinite(v))
  return { city, client, object_ids, tag_ids }
}

function pingStatusColor(status: string | null | undefined): string {
  if (status === 'online') return 'green'
  if (status === 'offline') return 'red'
  if (status === 'warn' || status === 'failed') return 'orange'
  return 'default'
}

function diskStatusColor(status: string | null | undefined): string {
  if (status === 'ok') return 'green'
  if (status === 'warn') return 'orange'
  if (status === 'failed') return 'red'
  return 'default'
}

function healthColor(score: number | null | undefined): string {
  if (score == null) return 'default'
  if (score >= 85) return 'green'
  if (score >= 65) return 'orange'
  return 'red'
}

function uptimeColor(point: DashboardAvailabilityPoint): string {
  if (point.samples === 0) return '#d9d9d9'
  if (point.offline > 0) return '#ff4d4f'
  return '#52c41a'
}

function UptimeBars({ points, compact = false }: { points: DashboardAvailabilityPoint[]; compact?: boolean }) {
  if (!points.length) {
    return <Typography.Text type="secondary">Нет точек в выбранном окне</Typography.Text>
  }
  return (
    <div style={{ display: 'flex', gap: compact ? 1 : 2, alignItems: 'center', height: compact ? 14 : 20 }}>
      {points.map((point, idx) => (
        <div
          key={`${point.bucket_start}-${idx}`}
          title={`${dayjs(point.bucket_start).format('DD.MM HH:mm')} • ${point.availability_pct ?? '—'}%`}
          style={{
            flex: 1,
            minWidth: compact ? 3 : 4,
            height: compact ? 9 : 14,
            borderRadius: compact ? 2 : 3,
            background: uptimeColor(point),
            border: '1px solid rgba(0,0,0,0.08)',
          }}
        />
      ))}
    </div>
  )
}

type PingFilter = 'all' | 'offline' | 'unknown' | 'online'

const PING_FILTER_OPTIONS: { value: PingFilter; label: string; color?: string }[] = [
  { value: 'all', label: 'Все' },
  { value: 'offline', label: 'Offline', color: '#ff4d4f' },
  { value: 'unknown', label: 'Unknown', color: '#fa8c16' },
  { value: 'online', label: 'Online', color: '#52c41a' },
]

export function HomeObjectDetailPage() {
  const navigate = useNavigate()
  const qc = useQueryClient()
  const { id } = useParams<{ id: string }>()
  const objectId = Number(id)
  const [search] = useSearchParams()
  const scope = useMemo(() => parseScope(search), [search])
  const [window, setWindow] = useState<DashboardAvailabilityWindow>('24h')
  const [pingFilter, setPingFilter] = useState<PingFilter>('all')

  const { data: summary, isLoading: summaryLoading } = useDashboardObjectSummary(objectId, scope)
  const { data: devices, isLoading: devicesLoading } = useDashboardObjectDevices(objectId, scope)
  const { data: availabilityData, isLoading: availabilityLoading } = useDashboardObjectAvailability(objectId, window, undefined, true)

  useDashboardMonitorSSE({
    onUpdate: () => {
      qc.invalidateQueries({ queryKey: ['dashboard-object-summary', objectId] })
      qc.invalidateQueries({ queryKey: ['dashboard-object-devices', objectId] })
      qc.invalidateQueries({ queryKey: ['dashboard-object-availability', objectId] })
    },
  })

  const object = summary?.object

  const availabilityByDevice = useMemo(() => {
    const map = new Map<number, { points: DashboardAvailabilityPoint[]; availability: number | null }>()
    for (const row of availabilityData?.devices ?? []) {
      map.set(row.device_id, { points: row.series ?? [], availability: row.availability_pct })
    }
    return map
  }, [availabilityData])

  const grouped = useMemo(() => {
    const rows = devices?.devices ?? []
    let online = 0, offline = 0, unknown = 0
    const byRack = new Map<string, DashboardDeviceNOCItem[]>()

    for (const row of rows) {
      if (row.ping_status === 'online') online++
      if (row.ping_status === 'offline') offline++
      if (row.ping_status === 'unknown') unknown++

      const rackName = row.rack_name?.trim() || 'Без стойки'
      if (!byRack.has(rackName)) byRack.set(rackName, [])
      byRack.get(rackName)!.push(row)
    }

    const rackGroups = Array.from(byRack.entries())
      .sort(([a], [b]) => {
        if (a === 'Без стойки') return -1
        if (b === 'Без стойки') return 1
        return a.localeCompare(b)
      })
      .map(([rack, rowsInRack]) => ({
        rack,
        rows: [...rowsInRack].sort((a, b) => {
          const order = { offline: 0, unknown: 1, online: 2 }
          const ao = order[a.ping_status as keyof typeof order] ?? 3
          const bo = order[b.ping_status as keyof typeof order] ?? 3
          if (ao !== bo) return ao - bo
          return a.ip.localeCompare(b.ip)
        }),
      }))

    return { online, offline, unknown, rackGroups }
  }, [devices])

  // Применяем фильтр по ping статусу к каждой стойке
  const filteredRackGroups = useMemo(() => {
    if (pingFilter === 'all') return grouped.rackGroups
    return grouped.rackGroups
      .map((rg) => ({ ...rg, rows: rg.rows.filter((r) => r.ping_status === pingFilter) }))
      .filter((rg) => rg.rows.length > 0)
  }, [grouped.rackGroups, pingFilter])

  const columns: ColumnsType<DashboardDeviceNOCItem> = [
    {
      title: 'IP / Hostname',
      key: 'identity',
      width: 190,
      render: (_, row) => (
        <Space direction="vertical" size={0} style={{ maxWidth: 170 }}>
          <code>{row.ip}</code>
          <Typography.Text type="secondary" ellipsis={{ tooltip: row.hostname ?? '—' }} style={{ fontSize: 12, maxWidth: 170 }}>
            {row.hostname ?? '—'}
          </Typography.Text>
        </Space>
      ),
    },
    {
      title: 'Категория',
      dataIndex: 'category',
      key: 'category',
      width: 110,
      ellipsis: true,
    },
    {
      title: 'Роль',
      key: 'role',
      width: 80,
      render: (_, row) => row.role ?? '—',
    },
    {
      title: 'Ping',
      key: 'ping',
      width: 130,
      render: (_, row) => (
        <Space direction="vertical" size={0}>
          <Tag color={pingStatusColor(row.ping_status)}>{row.ping_status}</Tag>
          <Typography.Text type="secondary" style={{ fontSize: 12 }}>
            {row.last_ping_ms != null ? `${row.last_ping_ms}ms` : '—'}
          </Typography.Text>
        </Space>
      ),
    },
    {
      title: 'Disk',
      key: 'disk',
      width: 90,
      render: (_, row) => {
        if (!row.disk_status) return <Typography.Text type="secondary">—</Typography.Text>
        return (
          <Space direction="vertical" size={0}>
            <Tag color={diskStatusColor(row.disk_status)}>{row.disk_status}</Tag>
            {row.disk_max_pct != null && (
              <Typography.Text type="secondary" style={{ fontSize: 12 }}>{row.disk_max_pct}%</Typography.Text>
            )}
          </Space>
        )
      },
    },
    {
      title: 'Uptime',
      key: 'uptime',
      width: 200,
      render: (_, row) => {
        const availability = availabilityByDevice.get(Number(row.device_id))
        if (availabilityLoading) return <Typography.Text type="secondary">Загрузка...</Typography.Text>
        if (!availability?.points?.length) return <Typography.Text type="secondary">Нет данных</Typography.Text>
        return (
          <Space direction="vertical" size={2} style={{ width: '100%' }}>
            <UptimeBars points={availability.points} compact />
            <Typography.Text type="secondary" style={{ fontSize: 12 }}>
              {availability.availability != null ? `${availability.availability}%` : '—'}
            </Typography.Text>
          </Space>
        )
      },
    },
  ]

  return (
    <div style={{ background: '#f4f6fb', margin: -12, padding: 12, borderRadius: 12 }}>
      <Row justify="space-between" align="middle" gutter={[8, 8]} style={{ marginBottom: 12 }}>
        <Col>
          <Space wrap>
            <Button icon={<ArrowLeftOutlined />} onClick={() => navigate('/home')}>
              Назад
            </Button>
            <Typography.Title level={4} style={{ margin: 0 }}>
              {object?.object_name ?? `Объект #${objectId}`}
            </Typography.Title>
          </Space>
        </Col>
        <Col>
          <Space wrap>
            {object?.allowed ? <Tag color="green">В мониторинге</Tag> : <Tag color="red">Вне мониторинга</Tag>}
            <Tag color={healthColor(object?.health_score)}>health {object?.health_score ?? '-'}</Tag>
            <Tag color="blue">окно {window}</Tag>
            <Button
              size="small"
              onClick={() => navigate(`/inventory/objects/${objectId}`)}
            >
              Инвентарь
            </Button>
          </Space>
        </Col>
      </Row>

      {object ? (
        <Typography.Text type="secondary" style={{ display: 'block', marginBottom: 12 }}>
          {reasonLabel(object.inclusion_reason)}
        </Typography.Text>
      ) : null}

      {availabilityData?.insufficient_data ? (
        <Alert
          type="info"
          showIcon
          style={{ marginBottom: 12 }}
          message="По части устройств данных пока недостаточно. Для новых объектов это нормально."
        />
      ) : null}

      {/* Счётчики */}
      <Row gutter={[12, 12]} style={{ marginBottom: 12 }}>
        <Col xs={12} md={6}>
          <Card size="small" loading={summaryLoading} style={{ borderRadius: 12 }}>
            <Typography.Text type="secondary">Устройств</Typography.Text>
            <Typography.Title level={3} style={{ margin: 0 }}>{summary?.totals.devices ?? 0}</Typography.Title>
          </Card>
        </Col>
        <Col xs={12} md={6}>
          <Card
            size="small"
            loading={devicesLoading}
            style={{ borderRadius: 12, cursor: 'pointer', outline: pingFilter === 'unknown' ? '2px solid #fa8c16' : undefined }}
            onClick={() => setPingFilter(pingFilter === 'unknown' ? 'all' : 'unknown')}
          >
            <Typography.Text type="secondary">Unknown</Typography.Text>
            <Typography.Title level={3} style={{ margin: 0, color: grouped.unknown > 0 ? '#fa8c16' : undefined }}>
              {grouped.unknown}
            </Typography.Title>
          </Card>
        </Col>
        <Col xs={12} md={6}>
          <Card
            size="small"
            loading={devicesLoading}
            style={{ borderRadius: 12, cursor: 'pointer', outline: pingFilter === 'offline' ? '2px solid #cf1322' : undefined }}
            onClick={() => setPingFilter(pingFilter === 'offline' ? 'all' : 'offline')}
          >
            <Typography.Text type="secondary">Offline</Typography.Text>
            <Typography.Title level={3} style={{ margin: 0, color: '#cf1322' }}>{grouped.offline}</Typography.Title>
          </Card>
        </Col>
        <Col xs={12} md={6}>
          <Card
            size="small"
            loading={devicesLoading}
            style={{ borderRadius: 12, cursor: 'pointer', outline: pingFilter === 'online' ? '2px solid #389e0d' : undefined }}
            onClick={() => setPingFilter(pingFilter === 'online' ? 'all' : 'online')}
          >
            <Typography.Text type="secondary">Online</Typography.Text>
            <Typography.Title level={3} style={{ margin: 0, color: '#389e0d' }}>{grouped.online}</Typography.Title>
          </Card>
        </Col>
      </Row>

      <Card
        title={
          <Row justify="space-between" align="middle" style={{ width: '100%' }}>
            <Space>
              <span>Устройства объекта</span>
              {pingFilter !== 'all' && (
                <Tag
                  color={PING_FILTER_OPTIONS.find((o) => o.value === pingFilter)?.color ? undefined : undefined}
                  style={{ background: PING_FILTER_OPTIONS.find((o) => o.value === pingFilter)?.color, color: '#fff', border: 'none' }}
                  closable
                  onClose={() => setPingFilter('all')}
                >
                  {PING_FILTER_OPTIONS.find((o) => o.value === pingFilter)?.label}
                </Tag>
              )}
            </Space>
          </Row>
        }
        size="small"
        style={{ borderRadius: 12 }}
        extra={
          <Space>
            <Space size={4}>
              {PING_FILTER_OPTIONS.map((opt) => (
                <Button
                  key={opt.value}
                  size="small"
                  type={pingFilter === opt.value ? 'primary' : 'default'}
                  style={
                    pingFilter === opt.value && opt.color
                      ? { background: opt.color, borderColor: opt.color }
                      : undefined
                  }
                  onClick={() => setPingFilter(opt.value)}
                >
                  {opt.label}
                </Button>
              ))}
            </Space>
            <Select
              value={window}
              onChange={(v) => setWindow(v as DashboardAvailabilityWindow)}
              options={[
                { value: '24h', label: '24ч' },
                { value: '3d', label: '3д' },
                { value: '7d', label: '7д' },
              ]}
              style={{ width: 80 }}
            />
          </Space>
        }
      >
        {!filteredRackGroups.length ? (
          <Empty
            image={Empty.PRESENTED_IMAGE_SIMPLE}
            description={pingFilter === 'all' ? 'Устройства не найдены' : `Нет устройств со статусом "${pingFilter}"`}
          />
        ) : (
          <Collapse
            defaultActiveKey={filteredRackGroups.map((rg) => rg.rack)}
            items={filteredRackGroups.map((rackGroup) => {
              const offlineCount = rackGroup.rows.filter((r) => r.ping_status === 'offline').length
              const unknownCount = rackGroup.rows.filter((r) => r.ping_status === 'unknown').length
              return {
                key: rackGroup.rack,
                label: (
                  <Space>
                    <span>{rackGroup.rack}</span>
                    <Tag>{rackGroup.rows.length}</Tag>
                    {offlineCount > 0 && <Tag color="red">offline: {offlineCount}</Tag>}
                    {unknownCount > 0 && <Tag color="orange">unknown: {unknownCount}</Tag>}
                  </Space>
                ),
                children: (
                  <Table<DashboardDeviceNOCItem>
                    loading={devicesLoading}
                    dataSource={rackGroup.rows}
                    rowKey="device_id"
                    size="small"
                    pagination={false}
                    columns={columns}
                    rowClassName={(row) =>
                      row.ping_status === 'offline' ? 'row-offline' : row.ping_status === 'unknown' ? 'row-unknown' : ''
                    }
                  />
                ),
              }
            })}
          />
        )}
      </Card>
    </div>
  )
}
