/**
 * Approval Store - HITL 授權狀態管理
 * ===================================
 * CISO-101: Multi-Sig 信任鏈前端整合
 *
 * Features:
 * - 輪詢 GET /api/v1/approvals/pending
 * - 簽核 POST /api/v1/approvals/{id}/sign
 * - 拒絕 POST /api/v1/approvals/{id}/reject
 * - Multi-Sig UX 狀態管理
 */

import { create } from 'zustand'
import { subscribeWithSelector } from 'zustand/middleware'
import type { ApprovalRequest as FrontendApprovalRequest } from '@/components/approval/approval-card'

// =============================================================================
// Types (與後端 Pydantic 模型對應)
// =============================================================================

export type ApprovalStatus = 'pending' | 'approved' | 'rejected' | 'expired'
export type RiskLevel = 'low' | 'medium' | 'critical'
export type DataImpact = 'none' | 'read_only' | 'write' | 'destructive'

export interface BlastRadius {
  affected_pods: number
  estimated_downtime: string
  related_services: string[]
  data_impact: DataImpact
}

export interface DryRunCheck {
  name: string
  passed: boolean
  message?: string | null
}

export interface Signature {
  id: string
  signer_id: string
  signer_name: string
  signed_at: string
  comment?: string | null
}

export interface ApprovalRequest {
  id: string
  action: string
  description: string
  status: ApprovalStatus
  risk_level: RiskLevel
  blast_radius: BlastRadius
  dry_run_checks: DryRunCheck[]
  required_signatures: number
  current_signatures: number
  signatures: Signature[]
  requested_by: string
  created_at: string
  expires_at: string | null
  resolved_at: string | null
  // 戰略 B: 告警風暴收斂
  fingerprint?: string | null
  hit_count?: number
  last_seen_at?: string | null
}

export interface SignResponse {
  success: boolean
  message: string
  approval: ApprovalRequest
  execution_triggered: boolean
}

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

type SSEConnectionStatus = 'disconnected' | 'connecting' | 'connected' | 'reconnecting' | 'error'

interface ApprovalState {
  // Data
  pendingApprovals: ApprovalRequest[]
  isLoading: boolean
  error: string | null
  lastFetched: Date | null

  // Signing state
  signingId: string | null
  rejectingId: string | null

  // Recently resolved (for animation)
  recentlyApproved: Set<string>
  recentlyRejected: Set<string>

  // SSE Connection (Phase 15: Polling → SSE)
  sseStatus: SSEConnectionStatus
  sseReconnectAttempts: number

  // Polling (Legacy, kept for fallback)
  pollingInterval: number | null

  // Actions
  fetchPending: () => Promise<void>
  // Phase 20: CSRF Token 參數 (可選，向後相容)
  signApproval: (id: string, signerId: string, signerName: string, comment?: string, csrfToken?: string) => Promise<SignResponse | null>
  rejectApproval: (id: string, rejectorId: string, rejectorName: string, reason: string, csrfToken?: string) => Promise<boolean>
  // SSE Actions (Phase 15)
  connectSSE: () => void
  disconnectSSE: () => void
  // Polling (Legacy)
  startPolling: (intervalMs?: number) => void
  stopPolling: () => void
  clearRecentlyResolved: (id: string) => void
  setError: (error: string | null) => void
}

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

const DEFAULT_POLLING_INTERVAL = 5000 // 5 seconds
const MAX_SSE_RECONNECT_ATTEMPTS = 10
const BASE_RECONNECT_DELAY = 1000 // 1 second
const MAX_RECONNECT_DELAY = 30000 // 30 seconds

// 統帥鐵律: 禁止任何 Fallback IP
const getApiBaseUrl = (): string => {
  if (typeof window === 'undefined') return ''
  const url = process.env.NEXT_PUBLIC_API_URL
  if (!url) {
    console.error('[AWOOOI ERROR] Missing NEXT_PUBLIC_API_URL')
    return ''
  }
  return url
}

const API_BASE_URL = getApiBaseUrl()

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

let pollingTimer: NodeJS.Timeout | null = null
let eventSource: EventSource | null = null
let sseReconnectTimeout: NodeJS.Timeout | null = null

export const useApprovalStore = create<ApprovalState>()(
  subscribeWithSelector((set, get) => ({
    // Initial state
    pendingApprovals: [],
    isLoading: false,
    error: null,
    lastFetched: null,
    signingId: null,
    rejectingId: null,
    recentlyApproved: new Set(),
    recentlyRejected: new Set(),
    // SSE state (Phase 15)
    sseStatus: 'disconnected',
    sseReconnectAttempts: 0,
    // Polling (Legacy)
    pollingInterval: null,

    // ==========================================================================
    // Fetch Pending Approvals
    // ==========================================================================
    fetchPending: async () => {
      set({ isLoading: true, error: null })

      try {
        const response = await fetch(`${API_BASE_URL}/api/v1/approvals/pending`)

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

        const data = await response.json()
        const approvals: ApprovalRequest[] = data.approvals || []

        console.log('[Approval] Fetched pending:', approvals.length)

        set({
          pendingApprovals: approvals,
          isLoading: false,
          lastFetched: new Date(),
        })
      } catch (err) {
        console.error('[Approval] Fetch failed:', err)
        set({
          isLoading: false,
          error: `Failed to fetch approvals: ${err}`,
        })
      }
    },

    // ==========================================================================
    // Sign Approval (Phase 15: Optimistic Updates)
    // ==========================================================================
    signApproval: async (id, signerId, signerName, comment, csrfToken) => {
      // 🔧 Race Condition 修復: 簽核期間暫停 Polling
      const wasPolling = pollingTimer !== null
      if (wasPolling) {
        clearInterval(pollingTimer!)
        pollingTimer = null
        console.log('[Approval] Polling paused during sign')
      }

      // 🎯 Phase 15: 樂觀更新 - 立即更新 UI (Optimistic Update)
      const state = get()
      const originalApprovals = [...state.pendingApprovals]
      const targetApproval = originalApprovals.find((a) => a.id === id)

      if (targetApproval) {
        // 樂觀更新: 假設簽核成功，立即增加簽章數
        const optimisticApproval = {
          ...targetApproval,
          current_signatures: targetApproval.current_signatures + 1,
          // 如果達到要求簽章數，預設為 approved
          status: (targetApproval.current_signatures + 1 >= targetApproval.required_signatures
            ? 'approved' : targetApproval.status) as ApprovalStatus,
        }

        set({
          pendingApprovals: state.pendingApprovals.map((a) =>
            a.id === id ? optimisticApproval : a
          ),
          signingId: id,
          error: null,
        })

        console.log('[Approval] Optimistic update applied:', id, {
          signatures: `${optimisticApproval.current_signatures}/${optimisticApproval.required_signatures}`,
          status: optimisticApproval.status,
        })
      } else {
        set({ signingId: id, error: null })
      }

      try {
        // Phase 20: CSRF Protection
        const headers: Record<string, string> = { 'Content-Type': 'application/json' }
        if (csrfToken) {
          headers['X-CSRF-Token'] = csrfToken
        }

        const response = await fetch(`${API_BASE_URL}/api/v1/approvals/${id}/sign`, {
          method: 'POST',
          headers,
          credentials: 'include', // Phase 20: 確保 cookie 被發送
          body: JSON.stringify({
            signer_id: signerId,
            signer_name: signerName,
            comment: comment || null,
          }),
        })

        if (!response.ok) {
          const errorData = await response.json().catch(() => ({}))
          throw new Error(errorData.detail || `HTTP ${response.status}`)
        }

        const result: SignResponse = await response.json()

        console.log('[Approval] Signed:', id, result.message)

        // Update local state
        // 🔴 2026-03-26 修復: 簽核後保留內容顯示，不立即移除
        set((state) => {
          const updatedApprovals = state.pendingApprovals.map((a) =>
            a.id === id ? result.approval : a
          )

          // If approved, mark for removal animation (但不立即移除)
          const newRecentlyApproved = new Set(state.recentlyApproved)
          if (result.approval.status === 'approved') {
            newRecentlyApproved.add(id)
          }

          return {
            // 🔴 修復: 保留在列表中，讓 UI 顯示已簽核狀態
            pendingApprovals: updatedApprovals,
            signingId: null,
            recentlyApproved: newRecentlyApproved,
          }
        })

        // 🔴 延遲 5 秒後才從列表移除 (讓用戶看到完整簽核結果)
        if (result.approval.status === 'approved') {
          setTimeout(() => {
            set((state) => ({
              pendingApprovals: state.pendingApprovals.filter((a) => a.id !== id),
            }))
            console.log('[Approval] Removed approved item after delay:', id)
          }, 5000)
        }

        // 🔧 Race Condition 修復: 延遲 1 秒後恢復 Polling，讓後端有時間更新
        if (wasPolling) {
          setTimeout(() => {
            get().startPolling(get().pollingInterval || DEFAULT_POLLING_INTERVAL)
            console.log('[Approval] Polling resumed after sign')
          }, 1000)
        }

        return result
      } catch (err) {
        console.error('[Approval] Sign failed:', err)

        // 🎯 Phase 15: 樂觀更新失敗 - 回滾到原始狀態 (Rollback)
        set({
          pendingApprovals: originalApprovals,
          signingId: null,
          error: `Sign failed: ${err}`,
        })
        console.log('[Approval] Rollback applied due to error')

        // 🔧 失敗也要恢復 Polling
        if (wasPolling) {
          get().startPolling(get().pollingInterval || DEFAULT_POLLING_INTERVAL)
          console.log('[Approval] Polling resumed after sign error')
        }

        return null
      }
    },

    // ==========================================================================
    // Reject Approval (Phase 15: Optimistic Updates)
    // ==========================================================================
    rejectApproval: async (id, rejectorId, rejectorName, reason, csrfToken) => {
      // 🔧 Race Condition 修復: 拒絕期間暫停 Polling
      const wasPolling = pollingTimer !== null
      if (wasPolling) {
        clearInterval(pollingTimer!)
        pollingTimer = null
        console.log('[Approval] Polling paused during reject')
      }

      // 🎯 Phase 15: 樂觀更新 - 立即更新 UI (Optimistic Update)
      const state = get()
      const originalApprovals = [...state.pendingApprovals]

      // 樂觀更新: 假設拒絕成功，立即更新狀態
      set({
        pendingApprovals: state.pendingApprovals.map((a) =>
          a.id === id ? { ...a, status: 'rejected' as ApprovalStatus } : a
        ),
        rejectingId: id,
        error: null,
      })

      console.log('[Approval] Optimistic reject applied:', id)

      try {
        // Phase 20: CSRF Protection
        const headers: Record<string, string> = { 'Content-Type': 'application/json' }
        if (csrfToken) {
          headers['X-CSRF-Token'] = csrfToken
        }

        const response = await fetch(`${API_BASE_URL}/api/v1/approvals/${id}/reject`, {
          method: 'POST',
          headers,
          credentials: 'include', // Phase 20: 確保 cookie 被發送
          body: JSON.stringify({
            rejector_id: rejectorId,
            rejector_name: rejectorName,
            reason,
          }),
        })

        if (!response.ok) {
          const errorData = await response.json().catch(() => ({}))
          throw new Error(errorData.detail || `HTTP ${response.status}`)
        }

        console.log('[Approval] Rejected:', id)

        // Update local state
        // 🔴 2026-03-26 修復: 拒絕後保留內容顯示，不立即移除
        set((state) => {
          const newRecentlyRejected = new Set(state.recentlyRejected)
          newRecentlyRejected.add(id)

          // 更新狀態但保留在列表中
          const updatedApprovals = state.pendingApprovals.map((a) =>
            a.id === id ? { ...a, status: 'rejected' as const } : a
          )

          return {
            pendingApprovals: updatedApprovals,
            rejectingId: null,
            recentlyRejected: newRecentlyRejected,
          }
        })

        // 🔴 延遲 5 秒後才從列表移除
        setTimeout(() => {
          set((state) => ({
            pendingApprovals: state.pendingApprovals.filter((a) => a.id !== id),
          }))
          console.log('[Approval] Removed rejected item after delay:', id)
        }, 5000)

        // 🔧 Race Condition 修復: 延遲 1 秒後恢復 Polling
        if (wasPolling) {
          setTimeout(() => {
            get().startPolling(get().pollingInterval || DEFAULT_POLLING_INTERVAL)
            console.log('[Approval] Polling resumed after reject')
          }, 1000)
        }

        return true
      } catch (err) {
        console.error('[Approval] Reject failed:', err)

        // 🎯 Phase 15: 樂觀更新失敗 - 回滾到原始狀態 (Rollback)
        set({
          pendingApprovals: originalApprovals,
          rejectingId: null,
          error: `Reject failed: ${err}`,
        })
        console.log('[Approval] Rollback applied due to reject error')

        // 🔧 失敗也要恢復 Polling
        if (wasPolling) {
          get().startPolling(get().pollingInterval || DEFAULT_POLLING_INTERVAL)
          console.log('[Approval] Polling resumed after reject error')
        }

        return false
      }
    },

    // ==========================================================================
    // SSE Connection (Phase 15: Polling → SSE)
    // ==========================================================================
    connectSSE: () => {
      const state = get()

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

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

      if (!API_BASE_URL) {
        console.error('[Approval SSE] Missing API URL')
        set({ sseStatus: 'error', error: 'Missing API URL' })
        return
      }

      set({ sseStatus: 'connecting', error: null })
      console.log('[Approval SSE] Connecting to', `${API_BASE_URL}/api/v1/approvals/stream`)

      // Initial fetch
      state.fetchPending()

      // Create EventSource
      eventSource = new EventSource(`${API_BASE_URL}/api/v1/approvals/stream`)

      eventSource.onopen = () => {
        console.log('[Approval SSE] Connected')
        set({
          sseStatus: 'connected',
          sseReconnectAttempts: 0,
          error: null,
        })
      }

      // Handle approval events (Phase 15: Incremental Updates)
      eventSource.addEventListener('approval', (e: MessageEvent) => {
        try {
          const data = JSON.parse(e.data) as {
            action: 'created' | 'signed' | 'rejected' | 'expired' | 'executed'
            approval_id: string
            approval?: ApprovalRequest
          }
          console.log('[Approval SSE] Event:', data.action, data.approval_id)

          // 🎯 Phase 15: 增量更新取代全量 re-fetch
          switch (data.action) {
            case 'created':
              // 新增: 如果有完整資料，直接加入列表
              if (data.approval) {
                set((state) => ({
                  pendingApprovals: [data.approval!, ...state.pendingApprovals],
                }))
              } else {
                // 無完整資料時才 re-fetch
                get().fetchPending()
              }
              break

            case 'signed':
              // 簽核: 更新或確認樂觀更新
              if (data.approval) {
                set((state) => ({
                  pendingApprovals: state.pendingApprovals.map((a) =>
                    a.id === data.approval_id ? data.approval! : a
                  ),
                }))
              }
              break

            case 'rejected':
            case 'expired':
            case 'executed':
              // 移除: 直接從列表移除 (延遲 2 秒讓 UI 顯示最終狀態)
              setTimeout(() => {
                set((state) => ({
                  pendingApprovals: state.pendingApprovals.filter(
                    (a) => a.id !== data.approval_id
                  ),
                }))
              }, 2000)
              break

            default:
              // 未知事件類型: re-fetch 作為 fallback
              get().fetchPending()
          }
        } catch (err) {
          console.error('[Approval SSE] Failed to parse event:', err)
        }
      })

      eventSource.addEventListener('heartbeat', () => {
        console.log('[Approval SSE] Heartbeat')
      })

      eventSource.addEventListener('connected', () => {
        console.log('[Approval SSE] Server confirmed connection')
      })

      // Error handling with exponential backoff
      eventSource.onerror = () => {
        const attempts = get().sseReconnectAttempts

        if (attempts >= MAX_SSE_RECONNECT_ATTEMPTS) {
          console.error('[Approval SSE] Max reconnect attempts reached, falling back to polling')
          set({ sseStatus: 'error', error: 'SSE connection failed' })
          eventSource?.close()
          eventSource = null
          // Fallback to polling
          get().startPolling()
          return
        }

        set({
          sseStatus: 'reconnecting',
          sseReconnectAttempts: attempts + 1,
        })

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

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

        if (sseReconnectTimeout) clearTimeout(sseReconnectTimeout)
        sseReconnectTimeout = setTimeout(() => {
          eventSource?.close()
          eventSource = null
          get().connectSSE()
        }, delay)
      }
    },

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

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

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

      set({ sseStatus: 'disconnected', sseReconnectAttempts: 0 })
    },

    // ==========================================================================
    // Polling (Legacy Fallback)
    // ==========================================================================
    startPolling: (intervalMs = DEFAULT_POLLING_INTERVAL) => {
      const state = get()

      // Clear existing timer
      if (pollingTimer) {
        clearInterval(pollingTimer)
      }

      // Initial fetch
      state.fetchPending()

      // Start polling
      pollingTimer = setInterval(() => {
        get().fetchPending()
      }, intervalMs)

      set({ pollingInterval: intervalMs })
      console.log('[Approval] Polling started:', intervalMs, 'ms')
    },

    stopPolling: () => {
      if (pollingTimer) {
        clearInterval(pollingTimer)
        pollingTimer = null
      }
      set({ pollingInterval: null })
      console.log('[Approval] Polling stopped')
    },

    clearRecentlyResolved: (id) => {
      set((state) => {
        const newApproved = new Set(state.recentlyApproved)
        const newRejected = new Set(state.recentlyRejected)
        newApproved.delete(id)
        newRejected.delete(id)
        return {
          recentlyApproved: newApproved,
          recentlyRejected: newRejected,
        }
      })
    },

    setError: (error) => {
      set({ error })
    },
  }))
)

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

export const usePendingApprovals = () =>
  useApprovalStore((state) => state.pendingApprovals)

export const useApprovalCount = () =>
  useApprovalStore((state) => state.pendingApprovals.length)

export const useApprovalById = (id: string) =>
  useApprovalStore((state) => state.pendingApprovals.find((a) => a.id === id))

export const useIsSigningApproval = (id: string) =>
  useApprovalStore((state) => state.signingId === id)

export const useIsRejectingApproval = (id: string) =>
  useApprovalStore((state) => state.rejectingId === id)

export const useApprovalError = () =>
  useApprovalStore((state) => state.error)

// SSE Status Hooks (Phase 15)
export const useApprovalSSEStatus = () =>
  useApprovalStore((state) => state.sseStatus)

export const useApprovalSSEConnected = () =>
  useApprovalStore((state) => state.sseStatus === 'connected')

// =============================================================================
// Type Converters (Backend → Frontend)
// =============================================================================

// P1 修復: 使用 mapping object 取代 toUpperCase() as Type (2026-03-26)
const DATA_IMPACT_MAP: Record<string, 'NONE' | 'READ_ONLY' | 'WRITE' | 'DESTRUCTIVE'> = {
  'none': 'NONE',
  'read_only': 'READ_ONLY',
  'read-only': 'READ_ONLY',
  'readonly': 'READ_ONLY',
  'write': 'WRITE',
  'destructive': 'DESTRUCTIVE',
  // 大寫版本 (防禦性)
  'NONE': 'NONE',
  'READ_ONLY': 'READ_ONLY',
  'WRITE': 'WRITE',
  'DESTRUCTIVE': 'DESTRUCTIVE',
}

export function toFrontendApproval(backend: ApprovalRequest): FrontendApprovalRequest {
  const rawDataImpact = backend.blast_radius.data_impact || 'none'
  const dataImpact = DATA_IMPACT_MAP[rawDataImpact] || DATA_IMPACT_MAP[rawDataImpact.toLowerCase()] || 'NONE'

  return {
    id: backend.id,
    action: backend.action,
    description: backend.description,
    riskLevel: backend.risk_level === 'critical' ? 'critical' :
               backend.risk_level === 'medium' ? 'medium' : 'low',
    blastRadius: {
      affectedPods: backend.blast_radius.affected_pods,
      estimatedDowntime: backend.blast_radius.estimated_downtime,
      relatedServices: backend.blast_radius.related_services,
      dataImpact,
    },
    dryRunChecks: backend.dry_run_checks.map((c) => ({
      name: c.name,
      passed: c.passed,
      message: c.message || undefined,
    })),
    requiredSignatures: backend.required_signatures,
    currentSignatures: backend.current_signatures,
    requestedBy: backend.requested_by,
    requestedAt: new Date(backend.created_at).toLocaleString('zh-TW'),
    // 戰略 B: 告警風暴收斂
    hitCount: backend.hit_count ?? 1,
    lastSeenAt: backend.last_seen_at || undefined,
    fingerprint: backend.fingerprint || undefined,
  }
}
