'use client'

import React, { useState, useEffect, useRef, useCallback } from 'react'
import './MonitoringDashboard.scss'

// ============================================================================
// Types
// ============================================================================

type Tab = 'health' | 'services' | 'performance' | 'alerts' | 'logs'

interface TabDefinition {
  key: Tab
  label: string
}

interface HealthData {
  cpuUsagePercent: number
  memoryUsagePercent: number
  diskUsagePercent: number
  uptime: number
  loadAvg1?: number
}

interface Snapshot {
  timestamp: string
  system?: {
    cpuUsagePercent?: number
    memoryUsagePercent?: number
    loadAvg1?: number
  }
  performance?: {
    avgResponseTimeMs?: number
    errorRate?: number
    requestsPerMinute?: number
  }
}

interface ServiceData {
  status: string
  [key: string]: unknown
}

interface ServicesResponse {
  postgresql?: ServiceData
  pgbouncer?: ServiceData
  redis?: ServiceData
  smtp?: ServiceData
  queues?: ServiceData
  oauth?: {
    metaOAuth?: { status: string; [key: string]: unknown }
    youtubeOAuth?: { status: string; [key: string]: unknown }
  }
}

interface PerformanceData {
  avgResponseTimeMs: number
  p95ResponseTimeMs: number
  p99ResponseTimeMs: number
  errorRate: number
  requestsPerMinute: number
}

interface AlertData {
  id: string
  severity: string
  metric: string
  message: string
  createdAt?: string
  acknowledgedBy?: string
}

interface LogData {
  id: string
  level: string
  source: string
  message: string
  createdAt?: string
  context?: Record<string, unknown>
}

interface TrendPoint {
  timestamp: string
  value: number
}

// ============================================================================
// Constants
// ============================================================================

const TABS: TabDefinition[] = [
  { key: 'health', label: 'System Health' },
  { key: 'services', label: 'Services' },
  { key: 'performance', label: 'Performance' },
  { key: 'alerts', label: 'Alerts' },
  { key: 'logs', label: 'Logs' },
]

const PERIOD_OPTIONS = ['1h', '6h', '24h', '7d'] as const

const LEVEL_COLORS: Record<string, string> = {
  debug: '#6b7280',
  info: '#3b82f6',
  warn: '#f59e0b',
  error: '#ef4444',
  fatal: '#dc2626',
}

const STATUS_COLORS: Record<string, string> = {
  online: '#22c55e',
  ok: '#22c55e',
  warning: '#f59e0b',
  expiring_soon: '#f59e0b',
  offline: '#ef4444',
  error: '#ef4444',
  expired: '#ef4444',
  unknown: '#6b7280',
}

const MAX_ALERTS_BUFFER = 50
const MAX_LOGS_BUFFER = 100

// ============================================================================
// Main Dashboard Component
// ============================================================================

export function MonitoringDashboard(): React.ReactElement {
  const [activeTab, setActiveTab] = useState<Tab>('health')
  const [connected, setConnected] = useState(false)
  const eventSourceRef = useRef<EventSource | null>(null)

  const [healthData, setHealthData] = useState<HealthData | null>(null)
  const [performanceData, setPerformanceData] = useState<PerformanceData | null>(null)
  const [newAlerts, setNewAlerts] = useState<AlertData[]>([])
  const [newLogs, setNewLogs] = useState<LogData[]>([])

  useEffect(() => {
    const es = new EventSource('/api/monitoring/stream', { withCredentials: true })
    eventSourceRef.current = es

    es.addEventListener('connected', () => setConnected(true))

    es.addEventListener('health', (e) => {
      try {
        setHealthData(JSON.parse(e.data))
      } catch (err) {
        console.error('[Monitoring] Failed to parse health event:', err)
      }
    })

    es.addEventListener('performance', (e) => {
      try {
        setPerformanceData(JSON.parse(e.data))
      } catch (err) {
        console.error('[Monitoring] Failed to parse performance event:', err)
      }
    })

    es.addEventListener('alert', (e) => {
      try {
        const alert: AlertData = JSON.parse(e.data)
        setNewAlerts((prev) => [alert, ...prev].slice(0, MAX_ALERTS_BUFFER))
      } catch (err) {
        console.error('[Monitoring] Failed to parse alert event:', err)
      }
    })

    es.addEventListener('log', (e) => {
      try {
        const log: LogData = JSON.parse(e.data)
        setNewLogs((prev) => [log, ...prev].slice(0, MAX_LOGS_BUFFER))
      } catch (err) {
        console.error('[Monitoring] Failed to parse log event:', err)
      }
    })

    es.addEventListener('reconnect', () => {
      es.close()
    })

    es.onerror = () => setConnected(false)

    return () => {
      es.close()
      eventSourceRef.current = null
    }
  }, [])

  const statusClass = connected ? 'monitoring__status--connected' : 'monitoring__status--disconnected'

  return (
    <div className="monitoring">
      <div className="monitoring__header">
        <h1 className="monitoring__title">Monitoring Dashboard</h1>
        <div className={`monitoring__status ${statusClass}`}>
          <span className="monitoring__status-dot" />
          {connected ? 'Live' : 'Disconnected'}
        </div>
      </div>

      <div className="monitoring__tabs">
        {TABS.map((tab) => (
          <button
            key={tab.key}
            className={`monitoring__tab ${activeTab === tab.key ? 'monitoring__tab--active' : ''}`}
            onClick={() => setActiveTab(tab.key)}
            type="button"
          >
            {tab.label}
          </button>
        ))}
      </div>

      <div className="monitoring__content">
        {activeTab === 'health' && <SystemHealthTab healthData={healthData} />}
        {activeTab === 'services' && <ServicesTab />}
        {activeTab === 'performance' && <PerformanceTab performanceData={performanceData} />}
        {activeTab === 'alerts' && <AlertsTab newAlerts={newAlerts} />}
        {activeTab === 'logs' && <LogsTab newLogs={newLogs} />}
      </div>
    </div>
  )
}

// ============================================================================
// Tab Components
// ============================================================================

interface SystemHealthTabProps {
  healthData: HealthData | null
}

function SystemHealthTab({ healthData }: SystemHealthTabProps): React.ReactElement {
  const [initialData, setInitialData] = useState<HealthData | null>(null)
  const [snapshots, setSnapshots] = useState<Snapshot[]>([])

  useEffect(() => {
    fetch('/api/monitoring/health', { credentials: 'include' })
      .then((r) => r.json())
      .then((d) => setInitialData(d.data))
      .catch((err) => console.error('[Monitoring] Failed to fetch health data:', err))

    fetch('/api/monitoring/snapshots?period=24h', { credentials: 'include' })
      .then((r) => r.json())
      .then((d) => setSnapshots(d.data || []))
      .catch((err) => console.error('[Monitoring] Failed to fetch snapshots:', err))
  }, [])

  const data = healthData || initialData

  if (!data) {
    return <div className="monitoring__loading">Loading...</div>
  }

  const uptimeHours = Math.round(data.uptime / 3600)

  return (
    <div className="monitoring__grid">
      <GaugeWidget label="CPU" value={data.cpuUsagePercent} max={100} unit="%" thresholds={{ warning: 70, critical: 90 }} />
      <GaugeWidget label="RAM" value={data.memoryUsagePercent} max={100} unit="%" thresholds={{ warning: 80, critical: 95 }} />
      <GaugeWidget label="Disk" value={data.diskUsagePercent} max={100} unit="%" thresholds={{ warning: 80, critical: 95 }} />
      <GaugeWidget label="Uptime" value={uptimeHours} max={720} unit="h" thresholds={{ warning: 0, critical: 0 }} />

      <div className="monitoring__chart-row">
        <TrendChart
          data={snapshots.map((s) => ({ timestamp: s.timestamp, value: s.system?.cpuUsagePercent || 0 }))}
          label="CPU (24h)"
          unit="%"
          height={200}
        />
        <TrendChart
          data={snapshots.map((s) => ({ timestamp: s.timestamp, value: s.system?.memoryUsagePercent || 0 }))}
          label="Memory (24h)"
          unit="%"
          height={200}
        />
        <TrendChart
          data={snapshots.map((s) => ({ timestamp: s.timestamp, value: s.system?.loadAvg1 || 0 }))}
          label="Load (24h)"
          unit=""
          height={200}
        />
      </div>
    </div>
  )
}

function ServicesTab(): React.ReactElement {
  const [services, setServices] = useState<ServicesResponse | null>(null)

  useEffect(() => {
    fetch('/api/monitoring/services', { credentials: 'include' })
      .then((r) => r.json())
      .then((d) => setServices(d.data))
      .catch((err) => console.error('[Monitoring] Failed to fetch services:', err))
  }, [])

  if (!services) {
    return <div className="monitoring__loading">Loading...</div>
  }

  const coreServices = [
    { name: 'PostgreSQL', data: services.postgresql },
    { name: 'PgBouncer', data: services.pgbouncer },
    { name: 'Redis', data: services.redis },
    { name: 'SMTP', data: services.smtp },
    { name: 'Queues', data: services.queues },
  ]

  return (
    <div className="monitoring__services">
      {coreServices.map((s) => (
        <div key={s.name} className="monitoring__service-card">
          <div className="monitoring__service-header">
            <StatusBadge status={s.data?.status || 'offline'} />
            <span className="monitoring__service-name">{s.name}</span>
          </div>
          <pre className="monitoring__service-details">{JSON.stringify(s.data, null, 2)}</pre>
        </div>
      ))}

      {services.oauth && (
        <>
          <ServiceOAuthCard name="Meta OAuth" data={services.oauth.metaOAuth} />
          <ServiceOAuthCard name="YouTube OAuth" data={services.oauth.youtubeOAuth} />
        </>
      )}
    </div>
  )
}

interface ServiceOAuthCardProps {
  name: string
  data?: { status: string; [key: string]: unknown }
}

function ServiceOAuthCard({ name, data }: ServiceOAuthCardProps): React.ReactElement {
  const status = data?.status === 'ok' ? 'online' : 'warning'

  return (
    <div className="monitoring__service-card">
      <div className="monitoring__service-header">
        <StatusBadge status={status} />
        <span className="monitoring__service-name">{name}</span>
      </div>
      <pre className="monitoring__service-details">{JSON.stringify(data, null, 2)}</pre>
    </div>
  )
}

interface PerformanceTabProps {
  performanceData: PerformanceData | null
}

function PerformanceTab({ performanceData }: PerformanceTabProps): React.ReactElement {
  const [period, setPeriod] = useState<string>('24h')
  const [metrics, setMetrics] = useState<PerformanceData | null>(null)
  const [snapshots, setSnapshots] = useState<Snapshot[]>([])

  useEffect(() => {
    fetch(`/api/monitoring/performance?period=${period}`, { credentials: 'include' })
      .then((r) => r.json())
      .then((d) => setMetrics(d.data))
      .catch((err) => console.error('[Monitoring] Failed to fetch performance data:', err))

    fetch(`/api/monitoring/snapshots?period=${period}`, { credentials: 'include' })
      .then((r) => r.json())
      .then((d) => setSnapshots(d.data || []))
      .catch((err) => console.error('[Monitoring] Failed to fetch snapshots:', err))
  }, [period])

  const data = performanceData || metrics

  return (
    <div className="monitoring__performance">
      <div className="monitoring__period-selector">
        {PERIOD_OPTIONS.map((p) => (
          <button
            key={p}
            className={`monitoring__period-btn ${period === p ? 'monitoring__period-btn--active' : ''}`}
            onClick={() => setPeriod(p)}
            type="button"
          >
            {p}
          </button>
        ))}
      </div>

      {data && (
        <div className="monitoring__kpi-row">
          <KpiCard value={`${data.avgResponseTimeMs}ms`} label="Avg Response" />
          <KpiCard value={`${data.p95ResponseTimeMs}ms`} label="P95" />
          <KpiCard value={`${data.p99ResponseTimeMs}ms`} label="P99" />
          <KpiCard value={`${(data.errorRate * 100).toFixed(1)}%`} label="Error Rate" />
          <KpiCard value={String(data.requestsPerMinute)} label="RPM" />
        </div>
      )}

      <div className="monitoring__chart-row">
        <TrendChart
          data={snapshots.map((s) => ({ timestamp: s.timestamp, value: s.performance?.avgResponseTimeMs || 0 }))}
          label="Avg Response Time"
          unit="ms"
          height={200}
        />
        <TrendChart
          data={snapshots.map((s) => ({ timestamp: s.timestamp, value: (s.performance?.errorRate || 0) * 100 }))}
          label="Error Rate"
          unit="%"
          height={200}
        />
        <TrendChart
          data={snapshots.map((s) => ({ timestamp: s.timestamp, value: s.performance?.requestsPerMinute || 0 }))}
          label="Requests/Min"
          unit=""
          height={200}
        />
      </div>
    </div>
  )
}

interface AlertsTabProps {
  newAlerts: AlertData[]
}

function AlertsTab({ newAlerts }: AlertsTabProps): React.ReactElement {
  const [alerts, setAlerts] = useState<AlertData[]>([])
  const [page, setPage] = useState(1)
  const [totalPages, setTotalPages] = useState(1)
  const [filter, setFilter] = useState<string>('')
  const [refreshCounter, setRefreshCounter] = useState(0)

  useEffect(() => {
    const params = new URLSearchParams({ page: String(page), limit: '20' })
    if (filter) {
      params.set('severity', filter)
    }

    fetch(`/api/monitoring/alerts?${params}`, { credentials: 'include' })
      .then((r) => r.json())
      .then((d) => {
        setAlerts(d.data || [])
        setTotalPages(d.totalPages || 1)
      })
      .catch((err) => console.error('[Monitoring] Failed to fetch alerts:', err))
  }, [page, filter, refreshCounter])

  const handleAcknowledge = useCallback(async (alertId: string) => {
    try {
      await fetch('/api/monitoring/alerts/acknowledge', {
        method: 'POST',
        credentials: 'include',
        headers: { 'Content-Type': 'application/json' },
        body: JSON.stringify({ alertId }),
      })
      setRefreshCounter((c) => c + 1)
    } catch (err) {
      console.error('[Monitoring] Failed to acknowledge alert:', err)
    }
  }, [])

  const newAlertIds = new Set(newAlerts.map((a) => a.id))
  const allAlerts = [...newAlerts, ...alerts.filter((a) => !newAlertIds.has(a.id))]

  return (
    <div className="monitoring__alerts">
      <div className="monitoring__alerts-toolbar">
        <select value={filter} onChange={(e) => setFilter(e.target.value)} className="monitoring__select">
          <option value="">Alle Severity</option>
          <option value="warning">Warning</option>
          <option value="error">Error</option>
          <option value="critical">Critical</option>
        </select>
        <a href="/admin/collections/monitoring-alert-rules" className="monitoring__link">
          Alert-Regeln verwalten
        </a>
      </div>

      <table className="monitoring__table">
        <thead>
          <tr>
            <th>Severity</th>
            <th>Metric</th>
            <th>Message</th>
            <th>Zeitpunkt</th>
            <th>Aktion</th>
          </tr>
        </thead>
        <tbody>
          {allAlerts.map((alert, i) => (
            <tr key={alert.id || i} className={!alert.acknowledgedBy ? 'monitoring__row--unack' : ''}>
              <td>
                <StatusBadge status={getAlertStatusColor(alert.severity)} />
              </td>
              <td>{alert.metric}</td>
              <td>{alert.message}</td>
              <td>{formatTimestamp(alert.createdAt)}</td>
              <td>
                {!alert.acknowledgedBy && (
                  <button
                    onClick={() => handleAcknowledge(alert.id)}
                    className="monitoring__btn monitoring__btn--sm"
                    type="button"
                  >
                    Bestätigen
                  </button>
                )}
              </td>
            </tr>
          ))}
          {allAlerts.length === 0 && (
            <tr>
              <td colSpan={5} className="monitoring__empty">
                Keine Alerts vorhanden
              </td>
            </tr>
          )}
        </tbody>
      </table>

      <Pagination page={page} totalPages={totalPages} onPageChange={setPage} />
    </div>
  )
}

interface LogsTabProps {
  newLogs: LogData[]
}

function LogsTab({ newLogs }: LogsTabProps): React.ReactElement {
  const [logs, setLogs] = useState<LogData[]>([])
  const [page, setPage] = useState(1)
  const [totalPages, setTotalPages] = useState(1)
  const [level, setLevel] = useState('')
  const [source, setSource] = useState('')
  const [searchInput, setSearchInput] = useState('')
  const [search, setSearch] = useState('')
  const [expanded, setExpanded] = useState<Set<string>>(new Set())

  // Debounce search input to avoid querying on every keystroke
  useEffect(() => {
    const timer = setTimeout(() => setSearch(searchInput), 300)
    return () => clearTimeout(timer)
  }, [searchInput])

  useEffect(() => {
    const params = new URLSearchParams({ page: String(page), limit: '50' })
    if (level) params.set('level', level)
    if (source) params.set('source', source)
    if (search) params.set('search', search)

    fetch(`/api/monitoring/logs?${params}`, { credentials: 'include' })
      .then((r) => r.json())
      .then((d) => {
        setLogs(d.data || [])
        setTotalPages(d.totalPages || 1)
      })
      .catch((err) => console.error('[Monitoring] Failed to fetch logs:', err))
  }, [page, level, source, search])

  const toggleExpand = useCallback((id: string) => {
    setExpanded((prev) => {
      const next = new Set(prev)
      if (next.has(id)) {
        next.delete(id)
      } else {
        next.add(id)
      }
      return next
    })
  }, [])

  const newLogIds = new Set(newLogs.map((l) => l.id))
  const allLogs = [...newLogs, ...logs.filter((l) => !newLogIds.has(l.id))]

  return (
    <div className="monitoring__logs">
      <div className="monitoring__logs-toolbar">
        <select value={level} onChange={(e) => setLevel(e.target.value)} className="monitoring__select">
          <option value="">Alle Level</option>
          <option value="debug">Debug</option>
          <option value="info">Info</option>
          <option value="warn">Warn</option>
          <option value="error">Error</option>
          <option value="fatal">Fatal</option>
        </select>
        <select value={source} onChange={(e) => setSource(e.target.value)} className="monitoring__select">
          <option value="">Alle Sources</option>
          <option value="payload">Payload</option>
          <option value="queue-worker">Queue Worker</option>
          <option value="cron">Cron</option>
          <option value="email">Email</option>
          <option value="oauth">OAuth</option>
          <option value="sync">Sync</option>
        </select>
        <input
          type="text"
          value={searchInput}
          onChange={(e) => setSearchInput(e.target.value)}
          placeholder="Suche..."
          className="monitoring__input"
        />
      </div>

      <table className="monitoring__table">
        <thead>
          <tr>
            <th>Level</th>
            <th>Source</th>
            <th>Message</th>
            <th>Zeitpunkt</th>
          </tr>
        </thead>
        <tbody>
          {allLogs.map((log, i) => (
            <React.Fragment key={log.id || i}>
              <tr
                onClick={() => log.context && toggleExpand(log.id)}
                className={log.context ? 'monitoring__row--clickable' : ''}
              >
                <td>
                  <span style={{ color: LEVEL_COLORS[log.level] || '#6b7280', fontWeight: 'bold' }}>
                    {log.level?.toUpperCase()}
                  </span>
                </td>
                <td>
                  <span className="monitoring__badge">{log.source}</span>
                </td>
                <td>{log.message}</td>
                <td>{formatTimestamp(log.createdAt)}</td>
              </tr>
              {expanded.has(log.id) && log.context && (
                <tr>
                  <td colSpan={4}>
                    <pre className="monitoring__json">{JSON.stringify(log.context, null, 2)}</pre>
                  </td>
                </tr>
              )}
            </React.Fragment>
          ))}
          {allLogs.length === 0 && (
            <tr>
              <td colSpan={4} className="monitoring__empty">
                Keine Logs vorhanden
              </td>
            </tr>
          )}
        </tbody>
      </table>

      <Pagination page={page} totalPages={totalPages} onPageChange={setPage} />
    </div>
  )
}

// ============================================================================
// Shared UI Components
// ============================================================================

interface StatusBadgeProps {
  status: string
}

function StatusBadge({ status }: StatusBadgeProps): React.ReactElement {
  const backgroundColor = STATUS_COLORS[status] || '#6b7280'

  return (
    <span className="monitoring__status-badge" style={{ backgroundColor }}>
      {status}
    </span>
  )
}

interface GaugeWidgetProps {
  label: string
  value: number
  max: number
  unit: string
  thresholds: { warning: number; critical: number }
}

function GaugeWidget({ label, value, max, unit, thresholds }: GaugeWidgetProps): React.ReactElement {
  const percent = Math.min((value / max) * 100, 100)
  const color = getThresholdColor(value, thresholds)

  return (
    <div className="monitoring__gauge">
      <div className="monitoring__gauge-label">{label}</div>
      <div className="monitoring__gauge-bar">
        <div className="monitoring__gauge-fill" style={{ width: `${percent}%`, backgroundColor: color }} />
      </div>
      <div className="monitoring__gauge-value">
        {value}
        {unit}
      </div>
    </div>
  )
}

interface TrendChartProps {
  data: TrendPoint[]
  label: string
  unit: string
  height: number
}

function TrendChart({ data, label, unit, height }: TrendChartProps): React.ReactElement {
  if (!data || data.length === 0) {
    return (
      <div className="monitoring__chart" style={{ height }}>
        <div className="monitoring__chart-label">{label}</div>
        <div className="monitoring__empty">Keine Daten</div>
      </div>
    )
  }

  const values = data.map((d) => d.value)
  const minVal = Math.min(...values)
  const maxVal = Math.max(...values)
  const range = maxVal - minVal || 1

  const width = 400
  const padding = 10
  const chartWidth = width - padding * 2
  const chartHeight = height - 40

  const points = data
    .map((d, i) => {
      const x = padding + (i / (data.length - 1 || 1)) * chartWidth
      const y = padding + chartHeight - ((d.value - minVal) / range) * chartHeight
      return `${x},${y}`
    })
    .join(' ')

  const lastValue = values[values.length - 1]

  return (
    <div className="monitoring__chart" style={{ height }}>
      <div className="monitoring__chart-header">
        <span className="monitoring__chart-label">{label}</span>
        <span className="monitoring__chart-value">
          {lastValue?.toFixed(1)}
          {unit}
        </span>
      </div>
      <svg viewBox={`0 0 ${width} ${height - 30}`} className="monitoring__chart-svg">
        <polyline fill="none" stroke="#3b82f6" strokeWidth="2" points={points} />
      </svg>
    </div>
  )
}

interface KpiCardProps {
  value: string
  label: string
}

function KpiCard({ value, label }: KpiCardProps): React.ReactElement {
  return (
    <div className="monitoring__kpi">
      <span className="monitoring__kpi-value">{value}</span>
      <span className="monitoring__kpi-label">{label}</span>
    </div>
  )
}

interface PaginationProps {
  page: number
  totalPages: number
  onPageChange: (page: number) => void
}

function Pagination({ page, totalPages, onPageChange }: PaginationProps): React.ReactElement | null {
  if (totalPages <= 1) {
    return null
  }

  return (
    <div className="monitoring__pagination">
      <button disabled={page <= 1} onClick={() => onPageChange(page - 1)} type="button">
        Zurück
      </button>
      <span>
        Seite {page} / {totalPages}
      </span>
      <button disabled={page >= totalPages} onClick={() => onPageChange(page + 1)} type="button">
        Weiter
      </button>
    </div>
  )
}

// ============================================================================
// Utility Functions
// ============================================================================

function getThresholdColor(value: number, thresholds: { warning: number; critical: number }): string {
  if (thresholds.critical > 0 && value >= thresholds.critical) {
    return '#ef4444'
  }
  if (thresholds.warning > 0 && value >= thresholds.warning) {
    return '#f59e0b'
  }
  return '#22c55e'
}

function getAlertStatusColor(severity: string): string {
  if (severity === 'critical') {
    return 'offline'
  }
  if (severity === 'error') {
    return 'warning'
  }
  return 'online'
}

function formatTimestamp(timestamp?: string): string {
  if (!timestamp) {
    return ''
  }
  return new Date(timestamp).toLocaleString('de-DE')
}
