import { AppstoreOutlined, BarsOutlined } from '@ant-design/icons'
import { useQueryClient } from '@tanstack/react-query'
import {
  Alert,
  Button,
  Card,
  Col,
  Empty,
  List,
  Progress,
  Row,
  Select,
  Space,
  Statistic,
  Tag,
  Typography,
  message,
} from 'antd'
import dayjs from 'dayjs'
import { useMemo, useState } from 'react'
import { useNavigate } from 'react-router-dom'
import { useObjects, useObjectsMeta } from '../api/objects'
import {
  useDashboardHomeSummary,
  useDashboardMonitorStatus,
  useDashboardRunNow,
  type DashboardScope,
  type DashboardObjectSummary,
} from '../api/dashboard'
import { useTags } from '../api/tags'
import { useDashboardMonitorSSE } from '../hooks/useDashboardMonitorSSE'
import {
  ObjectStatusCard,
  getSeverity,
  SEVERITY_COLOR,
  SEVERITY_LABEL,
  SEVERITY_TAG_COLOR,
  type Severity,
} from '../components/ObjectStatusCard'

const SEVERITY_ORDER: Record<Severity, number> = { critical: 0, degraded: 1, warn: 2, ok: 3 }

function formatAge(seconds: number | null | undefined): string {
  if (seconds == null) return '—'
  if (seconds < 60) return `${seconds}с`
  if (seconds < 3600) return `${Math.floor(seconds / 60)}м`
  return `${Math.floor(seconds / 3600)}ч ${Math.floor((seconds % 3600) / 60)}м`
}

function scopeToSearch(scope: DashboardScope): string {
  const params = new URLSearchParams()
  if (scope.city) params.set('city', scope.city)
  if (scope.client) params.set('client', scope.client)
  for (const id of scope.object_ids ?? []) params.append('object_ids', String(id))
  for (const id of scope.tag_ids ?? []) params.append('tag_ids', String(id))
  const raw = params.toString()
  return raw ? `?${raw}` : ''
}

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 runStatusColor(status: string | undefined): string {
  if (status === 'running') return 'processing'
  if (status === 'error') return 'red'
  if (status === 'idle') return 'blue'
  return 'default'
}

function toPct(numerator: number, denominator: number): number | null {
  if (denominator <= 0) return null
  return Math.round((numerator / denominator) * 1000) / 10
}

type ViewMode = 'grid' | 'list'

function getStoredViewMode(): ViewMode {
  try {
    const v = localStorage.getItem('noc-view-mode')
    if (v === 'grid' || v === 'list') return v
  } catch {}
  return 'grid'
}

const UNGROUPED_CITY = '__none__'

export function HomePage() {
  const qc = useQueryClient()
  const navigate = useNavigate()

  const { data: meta } = useObjectsMeta()
  const { data: objects } = useObjects()
  const { data: tags } = useTags()

  const [city, setCity] = useState<string | undefined>()
  const [client, setClient] = useState<string | undefined>()
  const [objectIds, setObjectIds] = useState<number[]>([])
  const [tagIds, setTagIds] = useState<number[]>([])
  const [severityFilter, setSeverityFilter] = useState<Severity | 'all'>('all')
  const [viewMode, setViewMode] = useState<ViewMode>(getStoredViewMode)

  const scope = useMemo(
    () => ({ city, client, object_ids: objectIds, tag_ids: tagIds }),
    [city, client, objectIds, tagIds]
  )

  const { data: summary, isLoading } = useDashboardHomeSummary(scope)
  const { data: monitorStatus } = useDashboardMonitorStatus()
  const runNow = useDashboardRunNow()

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

  const handleRunNow = async () => {
    try {
      const result = await runNow.mutateAsync({ ...scope, force: true })
      if (!result.accepted) {
        message.warning('Мониторинг уже запущен')
      } else {
        message.success('Мониторинг запущен')
      }
    } catch {
      message.error('Не удалось запустить мониторинг')
    }
  }

  const handleViewMode = (mode: ViewMode) => {
    setViewMode(mode)
    try { localStorage.setItem('noc-view-mode', mode) } catch {}
  }

  const totals = summary?.totals ?? { objects: 0, devices: 0, allowed_objects: 0, excluded_objects: 0 }
  const included = summary?.included_objects ?? []

  const pingInterval = useMemo(
    () => summary?.checks_meta?.find((c) => c.check_key === 'ping')?.interval_sec_default ?? 300,
    [summary]
  )
  const staleThreshold = pingInterval * 3

  const rankedObjects = useMemo(() => {
    return included
      .map((obj) => ({ obj, severity: getSeverity(obj, staleThreshold) }))
      .sort((a, b) => {
        const sd = SEVERITY_ORDER[a.severity] - SEVERITY_ORDER[b.severity]
        if (sd !== 0) return sd
        const aOff = a.obj.checks?.ping?.status_counts?.offline ?? 0
        const bOff = b.obj.checks?.ping?.status_counts?.offline ?? 0
        return bOff - aOff
      })
  }, [included, staleThreshold])

  const severityCounts = useMemo(() => {
    const counts: Record<Severity, number> = { critical: 0, degraded: 0, warn: 0, ok: 0 }
    for (const { severity } of rankedObjects) counts[severity]++
    return counts
  }, [rankedObjects])

  const filteredObjects = useMemo(() => {
    if (severityFilter === 'all') return rankedObjects
    return rankedObjects.filter((x) => x.severity === severityFilter)
  }, [rankedObjects, severityFilter])

  // Группировка по городу для grid-режима
  const cityGroups = useMemo(() => {
    const map = new Map<string, Array<{ obj: DashboardObjectSummary; severity: Severity }>>()
    for (const item of filteredObjects) {
      const key = item.obj.city ?? UNGROUPED_CITY
      if (!map.has(key)) map.set(key, [])
      map.get(key)!.push(item)
    }
    return [...map.entries()].sort(([a], [b]) => {
      if (a === UNGROUPED_CITY) return 1
      if (b === UNGROUPED_CITY) return -1
      return a.localeCompare(b, 'ru')
    })
  }, [filteredObjects])

  const offlineTotal = useMemo(
    () => included.reduce((acc, obj) => acc + (obj.checks?.ping?.status_counts?.offline ?? 0), 0),
    [included]
  )
  const unknownTotal = useMemo(
    () => included.reduce((acc, obj) => acc + (obj.checks?.ping?.status_counts?.unknown ?? 0), 0),
    [included]
  )
  const onlineTotal = useMemo(
    () => included.reduce((acc, obj) => acc + (obj.checks?.ping?.status_counts?.online ?? 0), 0),
    [included]
  )
  const diskWarnTotal = useMemo(
    () => included.reduce((acc, obj) => acc + (obj.checks?.disk_usage?.status_counts?.warn ?? 0), 0),
    [included]
  )
  const diskFailedTotal = useMemo(
    () => included.reduce((acc, obj) => acc + (obj.checks?.disk_usage?.status_counts?.failed ?? 0), 0),
    [included]
  )
  const stalePingObjects = useMemo(
    () => rankedObjects.filter((x) => (x.obj.checks?.ping?.max_age_sec ?? 0) > staleThreshold),
    [rankedObjects, staleThreshold]
  )
  const avgHealth = useMemo(() => {
    const values = included.map((x) => x.health_score).filter((v): v is number => v != null)
    if (!values.length) return null
    return Math.round(values.reduce((a, b) => a + b, 0) / values.length)
  }, [included])

  const monitoredTotal = onlineTotal + offlineTotal + unknownTotal
  const availabilityPct = toPct(onlineTotal, onlineTotal + offlineTotal)
  const coveragePct = toPct(summary?.included_count ?? totals.allowed_objects, totals.objects)
  const freshnessPct = toPct(
    Math.max(0, included.length - stalePingObjects.length),
    included.length
  )
  const signalCount = offlineTotal + unknownTotal + diskWarnTotal + diskFailedTotal
  const lastCounts = monitorStatus?.last_counts as Record<string, number> | null

  const systemSeverity: Severity =
    severityCounts.critical > 0 ? 'critical' :
    severityCounts.degraded > 0 ? 'degraded' :
    severityCounts.warn > 0 ? 'warn' : 'ok'

  return (
    <div style={{ background: '#f5f7fb', margin: -12, padding: 12, borderRadius: 12 }}>

      {/* Sticky статус-строка */}
      <div
        style={{
          position: 'sticky',
          top: 0,
          zIndex: 10,
          background: SEVERITY_COLOR[systemSeverity],
          borderRadius: 8,
          padding: '6px 16px',
          marginBottom: 12,
          display: 'flex',
          alignItems: 'center',
          gap: 24,
          flexWrap: 'wrap',
        }}
      >
        <Typography.Text strong style={{ color: '#fff', fontSize: 13, letterSpacing: 1 }}>
          {SEVERITY_LABEL[systemSeverity]}
        </Typography.Text>
        {(['critical', 'degraded', 'warn', 'ok'] as Severity[]).map((s) => (
          <span
            key={s}
            style={{
              color: '#fff',
              fontSize: 12,
              opacity: severityCounts[s] === 0 ? 0.5 : 1,
              cursor: 'pointer',
              fontWeight: severityFilter === s ? 700 : 400,
              textDecoration: severityFilter === s ? 'underline' : undefined,
            }}
            onClick={() => setSeverityFilter(severityFilter === s ? 'all' : s)}
          >
            {SEVERITY_LABEL[s]}: <strong>{severityCounts[s]}</strong>
          </span>
        ))}
        <span style={{ color: '#fff', fontSize: 12, marginLeft: 'auto', opacity: 0.85 }}>
          {monitorStatus?.last_success_at
            ? `обновлено ${dayjs(monitorStatus.last_success_at).format('HH:mm:ss')}`
            : 'нет данных'}
        </span>
      </div>

      {/* Заголовок */}
      <Row justify="space-between" align="middle" gutter={[8, 8]} style={{ marginBottom: 12 }}>
        <Col>
          <Typography.Title level={4} style={{ margin: 0 }}>NOC Dashboard</Typography.Title>
          <Typography.Text type="secondary">SLA, покрытие мониторингом, инциденты</Typography.Text>
        </Col>
        <Col>
          <Space wrap>
            <Button onClick={() => navigate(`/home/settings${scopeToSearch(scope)}`)}>
              Настройки мониторинга
            </Button>
            <Button type="primary" onClick={handleRunNow} loading={runNow.isPending}>
              Запустить сейчас
            </Button>
          </Space>
        </Col>
      </Row>

      {/* Фильтры */}
      <Card size="small" style={{ marginBottom: 12, borderRadius: 12 }}>
        <Row gutter={[8, 8]} align="middle">
          <Col xs={24} sm={12} lg={5}>
            <Select
              placeholder="Город"
              allowClear
              style={{ width: '100%' }}
              options={(meta?.cities ?? []).map((c) => ({ value: c, label: c }))}
              value={city}
              onChange={setCity}
            />
          </Col>
          <Col xs={24} sm={12} lg={5}>
            <Select
              placeholder="Клиент"
              allowClear
              style={{ width: '100%' }}
              options={(meta?.clients ?? []).map((c) => ({ value: c, label: c }))}
              value={client}
              onChange={setClient}
            />
          </Col>
          <Col xs={24} sm={12} lg={6}>
            <Select
              mode="multiple"
              placeholder="Объекты"
              allowClear
              style={{ width: '100%' }}
              value={objectIds}
              onChange={setObjectIds}
              options={(objects ?? []).map((o) => ({ value: o.id, label: o.name }))}
            />
          </Col>
          <Col xs={24} sm={12} lg={5}>
            <Select
              mode="multiple"
              placeholder="Теги"
              allowClear
              style={{ width: '100%' }}
              value={tagIds}
              onChange={setTagIds}
              options={(tags ?? []).map((t) => ({ value: t.id, label: t.name }))}
            />
          </Col>
          <Col xs={24} sm={24} lg={3}>
            <Select
              style={{ width: '100%' }}
              value={severityFilter}
              onChange={setSeverityFilter}
              options={[
                { value: 'all', label: 'Все' },
                { value: 'critical', label: 'Critical' },
                { value: 'degraded', label: 'Degraded' },
                { value: 'warn', label: 'Warn' },
                { value: 'ok', label: 'OK' },
              ]}
            />
          </Col>
        </Row>
      </Card>

      {/* Счётчики */}
      <Row gutter={[12, 12]} style={{ marginBottom: 12 }}>
        <Col xs={12} md={8} lg={4}>
          <Card size="small" loading={isLoading}><Statistic title="Объектов в скоупе" value={totals.objects} /></Card>
        </Col>
        <Col xs={12} md={8} lg={4}>
          <Card size="small" loading={isLoading}><Statistic title="Устройств" value={totals.devices} /></Card>
        </Col>
        <Col xs={12} md={8} lg={4}>
          <Card size="small" loading={isLoading}>
            <Statistic
              title="Проблемных объектов"
              value={severityCounts.critical + severityCounts.degraded}
              valueStyle={{ color: severityCounts.critical > 0 ? '#cf1322' : undefined }}
            />
          </Card>
        </Col>
        <Col xs={12} md={8} lg={4}>
          <Card size="small" loading={isLoading}><Statistic title="Сигналов проблем" value={signalCount} /></Card>
        </Col>
        <Col xs={12} md={8} lg={4}>
          <Card size="small" loading={isLoading}><Statistic title="Просроченных объектов" value={stalePingObjects.length} /></Card>
        </Col>
        <Col xs={12} md={8} lg={4}>
          <Card size="small" loading={isLoading}><Statistic title="Средний health" value={avgHealth ?? '—'} /></Card>
        </Col>
      </Row>

      {monitorStatus?.last_error && (
        <Alert type="error" showIcon style={{ marginBottom: 12 }} message={monitorStatus.last_error} />
      )}

      <Row gutter={[12, 12]}>
        {/* Основная панель объектов */}
        <Col xs={24} xl={16}>
          <Card
            size="small"
            style={{ borderRadius: 12 }}
            title={
              <Space>
                <span>Объекты</span>
                {severityFilter !== 'all' && (
                  <Tag color={SEVERITY_TAG_COLOR[severityFilter as Severity]}>
                    {SEVERITY_LABEL[severityFilter as Severity]}
                  </Tag>
                )}
                <Tag>{filteredObjects.length}</Tag>
              </Space>
            }
            extra={
              <Space size={4}>
                <Button
                  size="small"
                  icon={<AppstoreOutlined />}
                  type={viewMode === 'grid' ? 'primary' : 'default'}
                  onClick={() => handleViewMode('grid')}
                />
                <Button
                  size="small"
                  icon={<BarsOutlined />}
                  type={viewMode === 'list' ? 'primary' : 'default'}
                  onClick={() => handleViewMode('list')}
                />
              </Space>
            }
          >
            {filteredObjects.length === 0 ? (
              <Empty image={Empty.PRESENTED_IMAGE_SIMPLE} description="Нет объектов в выбранном фильтре" />
            ) : viewMode === 'grid' ? (
              // Grid-режим: плитки сгруппированные по городу
              <div style={{ display: 'flex', flexDirection: 'column', gap: 16 }}>
                {cityGroups.map(([cityKey, items]) => (
                  <div key={cityKey}>
                    <div style={{ display: 'flex', alignItems: 'center', gap: 8, marginBottom: 8 }}>
                      <Typography.Text strong style={{ fontSize: 13 }}>
                        {cityKey === UNGROUPED_CITY ? 'Без города' : cityKey}
                      </Typography.Text>
                      <Tag style={{ margin: 0 }}>{items.length}</Tag>
                      {/* Мини-счётчики severity для города */}
                      {(['critical', 'degraded', 'warn'] as Severity[]).map((s) => {
                        const cnt = items.filter((x) => x.severity === s).length
                        return cnt > 0 ? (
                          <Tag key={s} color={SEVERITY_TAG_COLOR[s]} style={{ margin: 0, fontSize: 11 }}>
                            {cnt}
                          </Tag>
                        ) : null
                      })}
                    </div>
                    <div
                      style={{
                        display: 'grid',
                        gridTemplateColumns: 'repeat(auto-fill, minmax(200px, 1fr))',
                        gap: 8,
                      }}
                    >
                      {items.map(({ obj, severity }) => (
                        <ObjectStatusCard
                          key={obj.object_id}
                          obj={obj}
                          severity={severity}
                          staleThreshold={staleThreshold}
                          scope={scope}
                        />
                      ))}
                    </div>
                  </div>
                ))}
              </div>
            ) : (
              // List-режим: строки с цветной полосой
              <List
                dataSource={filteredObjects}
                renderItem={({ obj, severity }) => {
                  const ping = obj.checks?.ping
                  const disk = obj.checks?.disk_usage?.status_counts ?? {}
                  const offline = ping?.status_counts?.offline ?? 0
                  const unknown = ping?.status_counts?.unknown ?? 0
                  const online = ping?.status_counts?.online ?? 0
                  const diskWarn = disk.warn ?? 0
                  const diskFailed = disk.failed ?? 0
                  const age = ping?.max_age_sec

                  return (
                    <List.Item
                      style={{
                        borderLeft: `3px solid ${SEVERITY_COLOR[severity]}`,
                        paddingLeft: 10,
                        background:
                          severity === 'critical' ? 'rgba(255,77,79,0.04)' :
                          severity === 'degraded' ? 'rgba(250,140,22,0.04)' : undefined,
                      }}
                      actions={[
                        <Button
                          key="open"
                          type="link"
                          onClick={() => navigate(`/home/objects/${obj.object_id}${scopeToSearch(scope)}`)}
                        >
                          Открыть
                        </Button>,
                      ]}
                    >
                      <List.Item.Meta
                        title={
                          <Space wrap size={6}>
                            <Typography.Text strong>{obj.object_name}</Typography.Text>
                            <Tag>{obj.city ?? '—'}</Tag>
                            <Tag color="blue">{obj.client ?? '—'}</Tag>
                            <Tag color={SEVERITY_TAG_COLOR[severity]}>{SEVERITY_LABEL[severity]}</Tag>
                            <Tag color={healthColor(obj.health_score)}>health {obj.health_score ?? '—'}</Tag>
                          </Space>
                        }
                        description={
                          <Space split={<span>·</span>} wrap size={4} style={{ fontSize: 12 }}>
                            <span style={{ color: online > 0 ? '#52c41a' : undefined }}>online: {online}</span>
                            {offline > 0 && <span style={{ color: '#ff4d4f' }}>offline: {offline}</span>}
                            {unknown > 0 && <span style={{ color: '#fa8c16' }}>unknown: {unknown}</span>}
                            {(diskWarn > 0 || diskFailed > 0) && (
                              <span style={{ color: diskFailed > 0 ? '#ff4d4f' : '#fa8c16' }}>
                                disk: {diskWarn}w/{diskFailed}f
                              </span>
                            )}
                            <span>устройств: {obj.device_count}</span>
                            {age != null && (
                              <span style={{ color: (age ?? 0) > staleThreshold ? '#fa8c16' : undefined }}>
                                age: {formatAge(age)}
                              </span>
                            )}
                          </Space>
                        }
                      />
                    </List.Item>
                  )
                }}
              />
            )}
          </Card>
        </Col>

        {/* Правая колонка */}
        <Col xs={24} xl={8}>
          <Space direction="vertical" size={12} style={{ width: '100%' }}>
            <Card title="SLA и покрытие" size="small" style={{ borderRadius: 12 }}>
              <Space direction="vertical" size={10} style={{ width: '100%' }}>
                <div>
                  <Row justify="space-between">
                    <Typography.Text>Доступность (online)</Typography.Text>
                    <Typography.Text strong>{availabilityPct != null ? `${availabilityPct}%` : '—'}</Typography.Text>
                  </Row>
                  <Progress
                    percent={availabilityPct ?? 0}
                    size="small"
                    showInfo={false}
                    strokeColor={availabilityPct != null && availabilityPct < 95 ? '#ff4d4f' : '#52c41a'}
                  />
                </div>
                <div>
                  <Row justify="space-between">
                    <Typography.Text>Покрытие мониторингом</Typography.Text>
                    <Typography.Text strong>{coveragePct != null ? `${coveragePct}%` : '—'}</Typography.Text>
                  </Row>
                  <Progress percent={coveragePct ?? 0} size="small" showInfo={false} strokeColor="#1677ff" />
                </div>
                <div>
                  <Row justify="space-between">
                    <Typography.Text>Свежесть данных</Typography.Text>
                    <Typography.Text strong>{freshnessPct != null ? `${freshnessPct}%` : '—'}</Typography.Text>
                  </Row>
                  <Progress
                    percent={freshnessPct ?? 0}
                    size="small"
                    showInfo={false}
                    strokeColor={freshnessPct != null && freshnessPct < 90 ? '#faad14' : '#52c41a'}
                  />
                </div>
                <Space wrap>
                  <Tag color="green">online: {onlineTotal}</Tag>
                  <Tag color="red">offline: {offlineTotal}</Tag>
                  <Tag color="orange">unknown: {unknownTotal}</Tag>
                  <Tag>по ping: {monitoredTotal}</Tag>
                </Space>
              </Space>
            </Card>

            <Card title="Состояние цикла мониторинга" size="small" style={{ borderRadius: 12 }}>
              <Space direction="vertical" size={8} style={{ width: '100%' }}>
                <Row justify="space-between">
                  <Typography.Text>Статус</Typography.Text>
                  <Tag color={runStatusColor(monitorStatus?.status)}>{monitorStatus?.status ?? '-'}</Tag>
                </Row>
                <Row justify="space-between">
                  <Typography.Text>Объекты в мониторинге</Typography.Text>
                  <Typography.Text strong>{summary?.included_count ?? totals.allowed_objects}</Typography.Text>
                </Row>
                <Row justify="space-between">
                  <Typography.Text>Последний успех</Typography.Text>
                  <Typography.Text strong>
                    {monitorStatus?.last_success_at
                      ? dayjs(monitorStatus.last_success_at).format('DD.MM HH:mm:ss')
                      : '—'}
                  </Typography.Text>
                </Row>
                {lastCounts && (
                  <Space direction="vertical" size={2} style={{ width: '100%' }}>
                    <Typography.Text type="secondary" style={{ fontSize: 12 }}>checks: {lastCounts.checks_executed ?? 0}</Typography.Text>
                    <Typography.Text type="secondary" style={{ fontSize: 12 }}>failed: {lastCounts.failed ?? 0}</Typography.Text>
                    <Typography.Text type="secondary" style={{ fontSize: 12 }}>checked devices: {lastCounts.devices_checked ?? 0}</Typography.Text>
                    <Typography.Text type="secondary" style={{ fontSize: 12 }}>skipped not due: {lastCounts.skipped_not_due ?? 0}</Typography.Text>
                  </Space>
                )}
              </Space>
            </Card>

            <Card title="Breakdown по severity" size="small" style={{ borderRadius: 12 }}>
              <Space direction="vertical" size={6} style={{ width: '100%' }}>
                {(['critical', 'degraded', 'warn', 'ok'] as Severity[]).map((s) => (
                  <div key={s}>
                    <Row justify="space-between" style={{ marginBottom: 2 }}>
                      <Typography.Text
                        style={{
                          cursor: 'pointer',
                          color: severityFilter === s ? SEVERITY_COLOR[s] : undefined,
                          fontWeight: severityFilter === s ? 600 : undefined,
                        }}
                        onClick={() => setSeverityFilter(severityFilter === s ? 'all' : s)}
                      >
                        {SEVERITY_LABEL[s]}
                      </Typography.Text>
                      <Typography.Text strong>{severityCounts[s]}</Typography.Text>
                    </Row>
                    <Progress
                      percent={
                        included.length > 0
                          ? Math.round((severityCounts[s] / included.length) * 100)
                          : 0
                      }
                      size="small"
                      showInfo={false}
                      strokeColor={SEVERITY_COLOR[s]}
                    />
                  </div>
                ))}
              </Space>
            </Card>
          </Space>
        </Col>
      </Row>
    </div>
  )
}
