'use client'

// =============================================================================
// TOM Generator Provider
// Context provider component for the TOM Generator Wizard
// =============================================================================

import React, {
  createContext,
  useReducer,
  useCallback,
  useEffect,
  useRef,
  ReactNode,
} from 'react'
import {
  TOMGeneratorState,
  TOMGeneratorStepId,
  CompanyProfile,
  DataProfile,
  ArchitectureProfile,
  SecurityProfile,
  RiskProfile,
  EvidenceDocument,
  DerivedTOM,
  ExportRecord,
  WizardStep,
  createInitialTOMGeneratorState,
  TOM_GENERATOR_STEPS,
  getStepIndex,
} from './types'
import { TOMRulesEngine } from './rules-engine'
import { tomGeneratorReducer, TOMGeneratorAction } from './reducer'

// =============================================================================
// CONTEXT VALUE INTERFACE
// =============================================================================

export interface TOMGeneratorContextValue {
  state: TOMGeneratorState
  dispatch: React.Dispatch<TOMGeneratorAction>

  // Navigation
  currentStepIndex: number
  totalSteps: number
  canGoNext: boolean
  canGoPrevious: boolean
  goToStep: (stepId: TOMGeneratorStepId) => void
  goToNextStep: () => void
  goToPreviousStep: () => void
  completeCurrentStep: (data: unknown) => void

  // Profile setters
  setCompanyProfile: (profile: CompanyProfile) => void
  updateCompanyProfile: (data: Partial<CompanyProfile>) => void
  setDataProfile: (profile: DataProfile) => void
  updateDataProfile: (data: Partial<DataProfile>) => void
  setArchitectureProfile: (profile: ArchitectureProfile) => void
  updateArchitectureProfile: (data: Partial<ArchitectureProfile>) => void
  setSecurityProfile: (profile: SecurityProfile) => void
  updateSecurityProfile: (data: Partial<SecurityProfile>) => void
  setRiskProfile: (profile: RiskProfile) => void
  updateRiskProfile: (data: Partial<RiskProfile>) => void

  // Evidence management
  addEvidence: (document: EvidenceDocument) => void
  updateEvidence: (id: string, data: Partial<EvidenceDocument>) => void
  deleteEvidence: (id: string) => void

  // TOM derivation
  deriveTOMs: () => void
  updateDerivedTOM: (id: string, data: Partial<DerivedTOM>) => void
  bulkUpdateTOMs: (updates: Array<{ id: string; data: Partial<DerivedTOM> }>) => void

  // Gap analysis
  runGapAnalysis: () => void

  // Export
  addExport: (record: ExportRecord) => void

  // Persistence
  saveState: () => Promise<void>
  loadState: () => Promise<void>
  resetState: () => void

  // Status
  isStepCompleted: (stepId: TOMGeneratorStepId) => boolean
  getCompletionPercentage: () => number
  isLoading: boolean
  error: string | null
}

// =============================================================================
// CONTEXT
// =============================================================================

export const TOMGeneratorContext = createContext<TOMGeneratorContextValue | null>(null)

// =============================================================================
// STORAGE KEYS
// =============================================================================

const STORAGE_KEY_PREFIX = 'tom-generator-state-'

function getStorageKey(tenantId: string): string {
  return `${STORAGE_KEY_PREFIX}${tenantId}`
}

// =============================================================================
// PROVIDER COMPONENT
// =============================================================================

interface TOMGeneratorProviderProps {
  children: ReactNode
  tenantId: string
  initialState?: TOMGeneratorState
  enablePersistence?: boolean
}

export function TOMGeneratorProvider({
  children,
  tenantId,
  initialState,
  enablePersistence = true,
}: TOMGeneratorProviderProps) {
  const [state, dispatch] = useReducer(
    tomGeneratorReducer,
    initialState ?? createInitialTOMGeneratorState(tenantId)
  )

  const [isLoading, setIsLoading] = React.useState(false)
  const [error, setError] = React.useState<string | null>(null)

  const rulesEngineRef = useRef<TOMRulesEngine | null>(null)

  // Initialize rules engine
  useEffect(() => {
    if (!rulesEngineRef.current) {
      rulesEngineRef.current = new TOMRulesEngine()
    }
  }, [])

  // Load state from localStorage on mount
  useEffect(() => {
    if (enablePersistence && typeof window !== 'undefined') {
      try {
        const stored = localStorage.getItem(getStorageKey(tenantId))
        if (stored) {
          const parsed = JSON.parse(stored)
          if (parsed.createdAt) parsed.createdAt = new Date(parsed.createdAt)
          if (parsed.updatedAt) parsed.updatedAt = new Date(parsed.updatedAt)
          if (parsed.steps) {
            parsed.steps = parsed.steps.map((step: WizardStep) => ({
              ...step,
              validatedAt: step.validatedAt ? new Date(step.validatedAt) : null,
            }))
          }
          if (parsed.documents) {
            parsed.documents = parsed.documents.map((doc: EvidenceDocument) => ({
              ...doc,
              uploadedAt: new Date(doc.uploadedAt),
              validFrom: doc.validFrom ? new Date(doc.validFrom) : null,
              validUntil: doc.validUntil ? new Date(doc.validUntil) : null,
              aiAnalysis: doc.aiAnalysis
                ? {
                    ...doc.aiAnalysis,
                    analyzedAt: new Date(doc.aiAnalysis.analyzedAt),
                  }
                : null,
            }))
          }
          if (parsed.derivedTOMs) {
            parsed.derivedTOMs = parsed.derivedTOMs.map((tom: DerivedTOM) => ({
              ...tom,
              implementationDate: tom.implementationDate
                ? new Date(tom.implementationDate)
                : null,
              reviewDate: tom.reviewDate ? new Date(tom.reviewDate) : null,
            }))
          }
          if (parsed.gapAnalysis?.generatedAt) {
            parsed.gapAnalysis.generatedAt = new Date(parsed.gapAnalysis.generatedAt)
          }
          if (parsed.exports) {
            parsed.exports = parsed.exports.map((exp: ExportRecord) => ({
              ...exp,
              generatedAt: new Date(exp.generatedAt),
            }))
          }
          dispatch({ type: 'LOAD_STATE', payload: parsed })
        }
      } catch (e) {
        console.error('Failed to load TOM Generator state from localStorage:', e)
      }
    }
  }, [tenantId, enablePersistence])

  // Save state to localStorage on changes
  useEffect(() => {
    if (enablePersistence && typeof window !== 'undefined') {
      try {
        localStorage.setItem(getStorageKey(tenantId), JSON.stringify(state))
      } catch (e) {
        console.error('Failed to save TOM Generator state to localStorage:', e)
      }
    }
  }, [state, tenantId, enablePersistence])

  // Navigation helpers
  const currentStepIndex = getStepIndex(state.currentStep)
  const totalSteps = TOM_GENERATOR_STEPS.length

  const canGoNext = currentStepIndex < totalSteps - 1
  const canGoPrevious = currentStepIndex > 0

  const goToStep = useCallback((stepId: TOMGeneratorStepId) => {
    dispatch({ type: 'SET_CURRENT_STEP', payload: stepId })
  }, [])

  const goToNextStep = useCallback(() => {
    if (canGoNext) {
      const nextStep = TOM_GENERATOR_STEPS[currentStepIndex + 1]
      dispatch({ type: 'SET_CURRENT_STEP', payload: nextStep.id })
    }
  }, [canGoNext, currentStepIndex])

  const goToPreviousStep = useCallback(() => {
    if (canGoPrevious) {
      const prevStep = TOM_GENERATOR_STEPS[currentStepIndex - 1]
      dispatch({ type: 'SET_CURRENT_STEP', payload: prevStep.id })
    }
  }, [canGoPrevious, currentStepIndex])

  const completeCurrentStep = useCallback(
    (data: unknown) => {
      dispatch({
        type: 'COMPLETE_STEP',
        payload: { stepId: state.currentStep, data },
      })
    },
    [state.currentStep]
  )

  // Profile setters
  const setCompanyProfile = useCallback((profile: CompanyProfile) => {
    dispatch({ type: 'SET_COMPANY_PROFILE', payload: profile })
  }, [])

  const updateCompanyProfile = useCallback((data: Partial<CompanyProfile>) => {
    dispatch({ type: 'UPDATE_COMPANY_PROFILE', payload: data })
  }, [])

  const setDataProfile = useCallback((profile: DataProfile) => {
    dispatch({ type: 'SET_DATA_PROFILE', payload: profile })
  }, [])

  const updateDataProfile = useCallback((data: Partial<DataProfile>) => {
    dispatch({ type: 'UPDATE_DATA_PROFILE', payload: data })
  }, [])

  const setArchitectureProfile = useCallback((profile: ArchitectureProfile) => {
    dispatch({ type: 'SET_ARCHITECTURE_PROFILE', payload: profile })
  }, [])

  const updateArchitectureProfile = useCallback(
    (data: Partial<ArchitectureProfile>) => {
      dispatch({ type: 'UPDATE_ARCHITECTURE_PROFILE', payload: data })
    },
    []
  )

  const setSecurityProfile = useCallback((profile: SecurityProfile) => {
    dispatch({ type: 'SET_SECURITY_PROFILE', payload: profile })
  }, [])

  const updateSecurityProfile = useCallback((data: Partial<SecurityProfile>) => {
    dispatch({ type: 'UPDATE_SECURITY_PROFILE', payload: data })
  }, [])

  const setRiskProfile = useCallback((profile: RiskProfile) => {
    dispatch({ type: 'SET_RISK_PROFILE', payload: profile })
  }, [])

  const updateRiskProfile = useCallback((data: Partial<RiskProfile>) => {
    dispatch({ type: 'UPDATE_RISK_PROFILE', payload: data })
  }, [])

  // Evidence management
  const addEvidence = useCallback((document: EvidenceDocument) => {
    dispatch({ type: 'ADD_EVIDENCE', payload: document })
  }, [])

  const updateEvidence = useCallback(
    (id: string, data: Partial<EvidenceDocument>) => {
      dispatch({ type: 'UPDATE_EVIDENCE', payload: { id, data } })
    },
    []
  )

  const deleteEvidence = useCallback((id: string) => {
    dispatch({ type: 'DELETE_EVIDENCE', payload: id })
  }, [])

  // TOM derivation
  const deriveTOMs = useCallback(() => {
    if (!rulesEngineRef.current) return

    const derivedTOMs = rulesEngineRef.current.deriveAllTOMs({
      companyProfile: state.companyProfile,
      dataProfile: state.dataProfile,
      architectureProfile: state.architectureProfile,
      securityProfile: state.securityProfile,
      riskProfile: state.riskProfile,
    })

    dispatch({ type: 'SET_DERIVED_TOMS', payload: derivedTOMs })
  }, [
    state.companyProfile,
    state.dataProfile,
    state.architectureProfile,
    state.securityProfile,
    state.riskProfile,
  ])

  const updateDerivedTOM = useCallback(
    (id: string, data: Partial<DerivedTOM>) => {
      dispatch({ type: 'UPDATE_DERIVED_TOM', payload: { id, data } })
    },
    []
  )

  const bulkUpdateTOMs = useCallback(
    (updates: Array<{ id: string; data: Partial<DerivedTOM> }>) => {
      for (const { id, data } of updates) {
        dispatch({ type: 'UPDATE_DERIVED_TOM', payload: { id, data } })
      }
    },
    []
  )

  // Gap analysis
  const runGapAnalysis = useCallback(() => {
    if (!rulesEngineRef.current) return

    const result = rulesEngineRef.current.performGapAnalysis(
      state.derivedTOMs,
      state.documents
    )

    dispatch({ type: 'SET_GAP_ANALYSIS', payload: result })
  }, [state.derivedTOMs, state.documents])

  // Export
  const addExport = useCallback((record: ExportRecord) => {
    dispatch({ type: 'ADD_EXPORT', payload: record })
  }, [])

  // Persistence
  const saveState = useCallback(async () => {
    setIsLoading(true)
    setError(null)
    try {
      const response = await fetch('/api/sdk/v1/tom-generator/state', {
        method: 'POST',
        headers: { 'Content-Type': 'application/json' },
        body: JSON.stringify({ tenantId, state }),
      })

      if (!response.ok) {
        throw new Error('Failed to save state')
      }
    } catch (e) {
      setError(e instanceof Error ? e.message : 'Unknown error')
      throw e
    } finally {
      setIsLoading(false)
    }
  }, [tenantId, state])

  const loadState = useCallback(async () => {
    setIsLoading(true)
    setError(null)
    try {
      const response = await fetch(
        `/api/sdk/v1/tom-generator/state?tenantId=${tenantId}`
      )

      if (!response.ok) {
        throw new Error('Failed to load state')
      }

      const data = await response.json()
      if (data.state) {
        dispatch({ type: 'LOAD_STATE', payload: data.state })
      }
    } catch (e) {
      setError(e instanceof Error ? e.message : 'Unknown error')
      throw e
    } finally {
      setIsLoading(false)
    }
  }, [tenantId])

  const resetState = useCallback(() => {
    dispatch({ type: 'RESET', payload: { tenantId } })
  }, [tenantId])

  // Status helpers
  const isStepCompleted = useCallback(
    (stepId: TOMGeneratorStepId) => {
      const step = state.steps.find((s) => s.id === stepId)
      return step?.completed ?? false
    },
    [state.steps]
  )

  const getCompletionPercentage = useCallback(() => {
    const completedSteps = state.steps.filter((s) => s.completed).length
    return Math.round((completedSteps / totalSteps) * 100)
  }, [state.steps, totalSteps])

  const contextValue: TOMGeneratorContextValue = {
    state,
    dispatch,

    currentStepIndex,
    totalSteps,
    canGoNext,
    canGoPrevious,
    goToStep,
    goToNextStep,
    goToPreviousStep,
    completeCurrentStep,

    setCompanyProfile,
    updateCompanyProfile,
    setDataProfile,
    updateDataProfile,
    setArchitectureProfile,
    updateArchitectureProfile,
    setSecurityProfile,
    updateSecurityProfile,
    setRiskProfile,
    updateRiskProfile,

    addEvidence,
    updateEvidence,
    deleteEvidence,

    deriveTOMs,
    updateDerivedTOM,
    bulkUpdateTOMs,

    runGapAnalysis,

    addExport,

    saveState,
    loadState,
    resetState,

    isStepCompleted,
    getCompletionPercentage,
    isLoading,
    error,
  }

  return (
    <TOMGeneratorContext.Provider value={contextValue}>
      {children}
    </TOMGeneratorContext.Provider>
  )
}
