/**
 * Dashboard Store - 戰情室狀態管理
 * =================================
 * Enterprise-grade SSE integration with Zustand
 *
 * Features:
 * - EventSource SSE 連線管理
 * - Hydration 模式 (snapshot + stream)
 * - 自動重連機制 (exponential backoff)
 * - Buffer 累積防止 JSON 切斷
 * - 資源清理 (AbortController)
 *
 * ADR-004: Zustand 狀態管理
 */

import { create } from 'zustand'
import { subscribeWithSelector } from 'zustand/middleware'

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

export type ConnectionStatus = 'disconnected' | 'connecting' | 'connected' | 'reconnecting' | 'error'

export type HostStatus = 'healthy' | 'degraded' | 'unhealthy' | 'unreachable'
export type ServiceStatus = 'up' | 'down' | 'degraded' | 'healthy' | 'warning' | 'critical' | 'thinking' | 'syncing' | 'idle'

export interface HostService {
  name: string
  status: ServiceStatus
  port: number | null
  latency_ms: number | null
  error: string | null
}

export interface BaselineData {
  baseline_value: number
  std_deviation: number
  sigma_deviation: number | null
  window_hours?: number
}

export interface HostMetrics {
  cpu_percent: number
  memory_percent: number
  disk_percent: number
  load_avg_1m: number
  uptime_hours: number
  // Dynamic Baseline
  cpu_baseline?: BaselineData | null
  memory_baseline?: BaselineData | null
}

export interface Host {
  ip: string
  name: string
  role: string
  status: HostStatus
  services: HostService[]
  metrics: HostMetrics | null
  last_check: string
}

export interface DashboardSnapshot {
  timestamp: string
  environment: string
  mock_mode: boolean
  overall_status: 'healthy' | 'degraded' | 'unhealthy'
  hosts: Host[]
  alerts_count: number
  pending_approvals: number
}

export interface SSEEvent {
  type: string
  data: Record<string, unknown>
  timestamp: string
  event_id: string
}

// =============================================================================
// Store State
// =============================================================================

interface DashboardState {
  // Connection
  connectionStatus: ConnectionStatus
  lastConnected: Date | null
  reconnectAttempts: number
  error: string | null

  // Data
  snapshot: DashboardSnapshot | null
  hosts: Host[]
  overallStatus: 'healthy' | 'degraded' | 'unhealthy'
  alertsCount: number
  pendingApprovals: number
  lastUpdate: Date | null
  mockMode: boolean

  // SSE Events buffer
  eventBuffer: SSEEvent[]

  // Actions
  connect: (apiBaseUrl: string) => void
  disconnect: () => void
  fetchSnapshot: (apiBaseUrl: string) => Promise<void>
  applySnapshot: (snapshot: DashboardSnapshot) => void
  applyHostUpdate: (data: Record<string, unknown>) => void
  setConnectionStatus: (status: ConnectionStatus) => void
  setError: (error: string | null) => void
  reset: () => void
}

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

const MAX_RECONNECT_ATTEMPTS = 10
const BASE_RECONNECT_DELAY = 1000 // 1 second
const MAX_RECONNECT_DELAY = 30000 // 30 seconds
const HEARTBEAT_TIMEOUT = 45000 // 45 seconds

// =============================================================================
// Store Implementation
// =============================================================================

// Store EventSource reference outside store to avoid serialization issues
let eventSource: EventSource | null = null
let reconnectTimeout: NodeJS.Timeout | null = null
let heartbeatTimeout: NodeJS.Timeout | null = null

export const useDashboardStore = create<DashboardState>()(
  subscribeWithSelector((set, get) => ({
    // Initial state
    connectionStatus: 'disconnected',
    lastConnected: null,
    reconnectAttempts: 0,
    error: null,
    snapshot: null,
    hosts: [],
    overallStatus: 'healthy',
    alertsCount: 0,
    pendingApprovals: 0,
    lastUpdate: null,
    mockMode: false,
    eventBuffer: [],

    // ==========================================================================
    // Actions
    // ==========================================================================

    connect: (apiBaseUrl: string) => {
      const state = get()

      // Already connected or connecting
      if (eventSource && state.connectionStatus === 'connected') {
        console.log('[SSE] Already connected')
        return
      }

      // Clean up existing connection
      if (eventSource) {
        eventSource.close()
        eventSource = null
      }

      // 統帥鐵律: 禁止任何 Fallback IP
      const resolvedApiBaseUrl = apiBaseUrl ||
        (typeof window !== 'undefined' ? process.env.NEXT_PUBLIC_API_URL : '')

      if (!resolvedApiBaseUrl) {
        console.error('[AWOOOI ERROR] Missing NEXT_PUBLIC_API_URL. SSE will not connect.')
        set({ connectionStatus: 'error', error: 'Missing API URL configuration' })
        return
      }

      set({ connectionStatus: 'connecting', error: null })
      console.log('[SSE] Connecting to', `${resolvedApiBaseUrl}/api/v1/dashboard/stream`)

      // Create EventSource
      eventSource = new EventSource(`${resolvedApiBaseUrl}/api/v1/dashboard/stream`)

      // Reset heartbeat on any event
      const resetHeartbeat = () => {
        if (heartbeatTimeout) clearTimeout(heartbeatTimeout)
        heartbeatTimeout = setTimeout(() => {
          console.warn('[SSE] Heartbeat timeout, reconnecting...')
          get().disconnect()
          setTimeout(() => get().connect(resolvedApiBaseUrl), 1000)
        }, HEARTBEAT_TIMEOUT)
      }

      // Connection opened
      eventSource.onopen = () => {
        console.log('[SSE] Connected')
        set({
          connectionStatus: 'connected',
          lastConnected: new Date(),
          reconnectAttempts: 0,
          error: null,
        })
        resetHeartbeat()

        // Hydration: Fetch snapshot after connection
        get().fetchSnapshot(resolvedApiBaseUrl)
      }

      // Handle events
      eventSource.addEventListener('connected', (_e: MessageEvent) => {
        console.log('[SSE] Received connected event')
        resetHeartbeat()
      })

      eventSource.addEventListener('host_update', (e: MessageEvent) => {
        try {
          const data = JSON.parse(e.data)
          console.log('[SSE] Host update:', data.overall_status)
          get().applyHostUpdate(data)
          resetHeartbeat()
        } catch (err) {
          console.error('[SSE] Failed to parse host_update:', err)
        }
      })

      eventSource.addEventListener('heartbeat', (_e: MessageEvent) => {
        console.log('[SSE] Heartbeat received')
        resetHeartbeat()
      })

      eventSource.addEventListener('alert', (e: MessageEvent) => {
        try {
          const data = JSON.parse(e.data)
          console.log('[SSE] Alert:', data)
          set((state) => ({
            alertsCount: state.alertsCount + 1,
            eventBuffer: [...state.eventBuffer.slice(-99), { type: 'alert', ...data }],
          }))
          resetHeartbeat()
        } catch (err) {
          console.error('[SSE] Failed to parse alert:', err)
        }
      })

      // Error handling with exponential backoff
      eventSource.onerror = (e) => {
        console.error('[SSE] Error:', e)

        const attempts = get().reconnectAttempts

        if (attempts >= MAX_RECONNECT_ATTEMPTS) {
          set({
            connectionStatus: 'error',
            error: 'Max reconnection attempts reached',
          })
          eventSource?.close()
          eventSource = null
          return
        }

        set({
          connectionStatus: 'reconnecting',
          reconnectAttempts: attempts + 1,
        })

        // Exponential backoff
        const delay = Math.min(
          BASE_RECONNECT_DELAY * Math.pow(2, attempts),
          MAX_RECONNECT_DELAY
        )

        console.log(`[SSE] Reconnecting in ${delay}ms (attempt ${attempts + 1})`)

        if (reconnectTimeout) clearTimeout(reconnectTimeout)
        reconnectTimeout = setTimeout(() => {
          eventSource?.close()
          eventSource = null
          get().connect(resolvedApiBaseUrl)
        }, delay)
      }
    },

    disconnect: () => {
      console.log('[SSE] Disconnecting...')

      if (eventSource) {
        eventSource.close()
        eventSource = null
      }

      if (reconnectTimeout) {
        clearTimeout(reconnectTimeout)
        reconnectTimeout = null
      }

      if (heartbeatTimeout) {
        clearTimeout(heartbeatTimeout)
        heartbeatTimeout = null
      }

      set({
        connectionStatus: 'disconnected',
        reconnectAttempts: 0,
      })
    },

    fetchSnapshot: async (apiBaseUrl: string) => {
      // 統帥鐵律: 禁止任何 Fallback IP
      const resolvedApiBaseUrl = apiBaseUrl ||
        (typeof window !== 'undefined' ? process.env.NEXT_PUBLIC_API_URL : '')

      if (!resolvedApiBaseUrl) {
        console.error('[AWOOOI ERROR] Missing API URL for snapshot fetch')
        return
      }

      try {
        console.log('[SSE] Fetching snapshot for hydration from:', resolvedApiBaseUrl)
        const response = await fetch(`${resolvedApiBaseUrl}/api/v1/dashboard/snapshot`)

        if (!response.ok) {
          throw new Error(`HTTP ${response.status}`)
        }

        const snapshot: DashboardSnapshot = await response.json()
        get().applySnapshot(snapshot)
        console.log('[SSE] Snapshot applied, hosts:', snapshot.hosts.length)
      } catch (err) {
        console.error('[SSE] Failed to fetch snapshot:', err)
        set({ error: `Snapshot fetch failed: ${err}` })
      }
    },

    applySnapshot: (snapshot: DashboardSnapshot) => {
      set({
        snapshot,
        hosts: snapshot.hosts,
        overallStatus: snapshot.overall_status,
        alertsCount: snapshot.alerts_count,
        pendingApprovals: snapshot.pending_approvals,
        lastUpdate: new Date(snapshot.timestamp),
        mockMode: snapshot.mock_mode,
      })
    },

    applyHostUpdate: (data: Record<string, unknown>) => {
      const hostsData = data.hosts as Array<{
        ip: string
        name: string
        status: HostStatus
        metrics?: {
          cpu_percent: number
          memory_percent: number
          cpu_baseline?: BaselineData | null
          memory_baseline?: BaselineData | null
        } | null
      }>

      if (!hostsData) return

      set((state) => {
        // Merge updates with existing hosts (including baseline data)
        const updatedHosts = state.hosts.map((host) => {
          const update = hostsData.find((h) => h.ip === host.ip)
          if (update) {
            return {
              ...host,
              status: update.status,
              metrics: update.metrics
                ? {
                    ...host.metrics,
                    cpu_percent: update.metrics.cpu_percent,
                    memory_percent: update.metrics.memory_percent,
                    // Preserve baseline from snapshot (SSE updates don't include baseline)
                    cpu_baseline: update.metrics.cpu_baseline ?? host.metrics?.cpu_baseline,
                    memory_baseline: update.metrics.memory_baseline ?? host.metrics?.memory_baseline,
                  } as HostMetrics
                : host.metrics,
            }
          }
          return host
        })

        return {
          hosts: updatedHosts,
          overallStatus: (data.overall_status as 'healthy' | 'degraded' | 'unhealthy') || state.overallStatus,
          lastUpdate: new Date(),
        }
      })
    },

    setConnectionStatus: (status: ConnectionStatus) => {
      set({ connectionStatus: status })
    },

    setError: (error: string | null) => {
      set({ error })
    },

    reset: () => {
      get().disconnect()
      set({
        connectionStatus: 'disconnected',
        lastConnected: null,
        reconnectAttempts: 0,
        error: null,
        snapshot: null,
        hosts: [],
        overallStatus: 'healthy',
        alertsCount: 0,
        pendingApprovals: 0,
        lastUpdate: null,
        mockMode: false,
        eventBuffer: [],
      })
    },
  }))
)

// =============================================================================
// Selector Hooks
// =============================================================================

export const useConnectionStatus = () =>
  useDashboardStore((state) => state.connectionStatus)

export const useConnectionError = () =>
  useDashboardStore((state) => state.error)

export const useHosts = () =>
  useDashboardStore((state) => state.hosts)

export const useHostByIp = (ip: string) =>
  useDashboardStore((state) => state.hosts.find((h) => h.ip === ip))

export const useOverallStatus = () =>
  useDashboardStore((state) => state.overallStatus)

export const useAlerts = () =>
  useDashboardStore((state) => ({
    count: state.alertsCount,
    pending: state.pendingApprovals,
  }))

export const useMockMode = () =>
  useDashboardStore((state) => state.mockMode)

export const useLastUpdate = () =>
  useDashboardStore((state) => state.lastUpdate)
