'use client'

// =============================================================================
// TOM Generator Context
// State management for the TOM Generator Wizard
// =============================================================================

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

// =============================================================================
// ACTION TYPES
// =============================================================================

type TOMGeneratorAction =
  | { type: 'INITIALIZE'; payload: { tenantId: string; state?: TOMGeneratorState } }
  | { type: 'RESET'; payload: { tenantId: string } }
  | { type: 'SET_CURRENT_STEP'; payload: TOMGeneratorStepId }
  | { type: 'SET_COMPANY_PROFILE'; payload: CompanyProfile }
  | { type: 'UPDATE_COMPANY_PROFILE'; payload: Partial<CompanyProfile> }
  | { type: 'SET_DATA_PROFILE'; payload: DataProfile }
  | { type: 'UPDATE_DATA_PROFILE'; payload: Partial<DataProfile> }
  | { type: 'SET_ARCHITECTURE_PROFILE'; payload: ArchitectureProfile }
  | { type: 'UPDATE_ARCHITECTURE_PROFILE'; payload: Partial<ArchitectureProfile> }
  | { type: 'SET_SECURITY_PROFILE'; payload: SecurityProfile }
  | { type: 'UPDATE_SECURITY_PROFILE'; payload: Partial<SecurityProfile> }
  | { type: 'SET_RISK_PROFILE'; payload: RiskProfile }
  | { type: 'UPDATE_RISK_PROFILE'; payload: Partial<RiskProfile> }
  | { type: 'COMPLETE_STEP'; payload: { stepId: TOMGeneratorStepId; data: unknown } }
  | { type: 'UNCOMPLETE_STEP'; payload: TOMGeneratorStepId }
  | { type: 'ADD_EVIDENCE'; payload: EvidenceDocument }
  | { type: 'UPDATE_EVIDENCE'; payload: { id: string; data: Partial<EvidenceDocument> } }
  | { type: 'DELETE_EVIDENCE'; payload: string }
  | { type: 'SET_DERIVED_TOMS'; payload: DerivedTOM[] }
  | { type: 'UPDATE_DERIVED_TOM'; payload: { id: string; data: Partial<DerivedTOM> } }
  | { type: 'SET_GAP_ANALYSIS'; payload: GapAnalysisResult }
  | { type: 'ADD_EXPORT'; payload: ExportRecord }
  | { type: 'BULK_UPDATE_TOMS'; payload: { updates: Array<{ id: string; data: Partial<DerivedTOM> }> } }
  | { type: 'LOAD_STATE'; payload: TOMGeneratorState }

// =============================================================================
// REDUCER
// =============================================================================

function tomGeneratorReducer(
  state: TOMGeneratorState,
  action: TOMGeneratorAction
): TOMGeneratorState {
  const updateState = (updates: Partial<TOMGeneratorState>): TOMGeneratorState => ({
    ...state,
    ...updates,
    updatedAt: new Date(),
  })

  switch (action.type) {
    case 'INITIALIZE': {
      if (action.payload.state) {
        return action.payload.state
      }
      return createInitialTOMGeneratorState(action.payload.tenantId)
    }

    case 'RESET': {
      return createInitialTOMGeneratorState(action.payload.tenantId)
    }

    case 'SET_CURRENT_STEP': {
      return updateState({ currentStep: action.payload })
    }

    case 'SET_COMPANY_PROFILE': {
      return updateState({ companyProfile: action.payload })
    }

    case 'UPDATE_COMPANY_PROFILE': {
      if (!state.companyProfile) return state
      return updateState({
        companyProfile: { ...state.companyProfile, ...action.payload },
      })
    }

    case 'SET_DATA_PROFILE': {
      // Automatically set hasSpecialCategories based on categories
      const profile: DataProfile = {
        ...action.payload,
        hasSpecialCategories: hasSpecialCategories(action.payload.categories),
      }
      return updateState({ dataProfile: profile })
    }

    case 'UPDATE_DATA_PROFILE': {
      if (!state.dataProfile) return state
      const updatedProfile = { ...state.dataProfile, ...action.payload }
      // Recalculate hasSpecialCategories if categories changed
      if (action.payload.categories) {
        updatedProfile.hasSpecialCategories = hasSpecialCategories(
          action.payload.categories
        )
      }
      return updateState({ dataProfile: updatedProfile })
    }

    case 'SET_ARCHITECTURE_PROFILE': {
      return updateState({ architectureProfile: action.payload })
    }

    case 'UPDATE_ARCHITECTURE_PROFILE': {
      if (!state.architectureProfile) return state
      return updateState({
        architectureProfile: { ...state.architectureProfile, ...action.payload },
      })
    }

    case 'SET_SECURITY_PROFILE': {
      return updateState({ securityProfile: action.payload })
    }

    case 'UPDATE_SECURITY_PROFILE': {
      if (!state.securityProfile) return state
      return updateState({
        securityProfile: { ...state.securityProfile, ...action.payload },
      })
    }

    case 'SET_RISK_PROFILE': {
      // Automatically calculate protection level and DSFA requirement
      const profile: RiskProfile = {
        ...action.payload,
        protectionLevel: calculateProtectionLevel(action.payload.ciaAssessment),
        dsfaRequired: isDSFARequired(state.dataProfile, action.payload),
      }
      return updateState({ riskProfile: profile })
    }

    case 'UPDATE_RISK_PROFILE': {
      if (!state.riskProfile) return state
      const updatedProfile = { ...state.riskProfile, ...action.payload }
      // Recalculate protection level if CIA assessment changed
      if (action.payload.ciaAssessment) {
        updatedProfile.protectionLevel = calculateProtectionLevel(
          action.payload.ciaAssessment
        )
      }
      // Recalculate DSFA requirement
      updatedProfile.dsfaRequired = isDSFARequired(state.dataProfile, updatedProfile)
      return updateState({ riskProfile: updatedProfile })
    }

    case 'COMPLETE_STEP': {
      const updatedSteps = state.steps.map((step) =>
        step.id === action.payload.stepId
          ? {
              ...step,
              completed: true,
              data: action.payload.data,
              validatedAt: new Date(),
            }
          : step
      )
      return updateState({ steps: updatedSteps })
    }

    case 'UNCOMPLETE_STEP': {
      const updatedSteps = state.steps.map((step) =>
        step.id === action.payload
          ? { ...step, completed: false, validatedAt: null }
          : step
      )
      return updateState({ steps: updatedSteps })
    }

    case 'ADD_EVIDENCE': {
      return updateState({
        documents: [...state.documents, action.payload],
      })
    }

    case 'UPDATE_EVIDENCE': {
      const updatedDocuments = state.documents.map((doc) =>
        doc.id === action.payload.id ? { ...doc, ...action.payload.data } : doc
      )
      return updateState({ documents: updatedDocuments })
    }

    case 'DELETE_EVIDENCE': {
      return updateState({
        documents: state.documents.filter((doc) => doc.id !== action.payload),
      })
    }

    case 'SET_DERIVED_TOMS': {
      return updateState({ derivedTOMs: action.payload })
    }

    case 'UPDATE_DERIVED_TOM': {
      const updatedTOMs = state.derivedTOMs.map((tom) =>
        tom.id === action.payload.id ? { ...tom, ...action.payload.data } : tom
      )
      return updateState({ derivedTOMs: updatedTOMs })
    }

    case 'SET_GAP_ANALYSIS': {
      return updateState({ gapAnalysis: action.payload })
    }

    case 'ADD_EXPORT': {
      return updateState({
        exports: [...state.exports, action.payload],
      })
    }

    case 'BULK_UPDATE_TOMS': {
      let updatedTOMs = [...state.derivedTOMs]
      for (const update of action.payload.updates) {
        updatedTOMs = updatedTOMs.map((tom) =>
          tom.id === update.id ? { ...tom, ...update.data } : tom
        )
      }
      return updateState({ derivedTOMs: updatedTOMs })
    }

    case 'LOAD_STATE': {
      return action.payload
    }

    default:
      return state
  }
}

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

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
// =============================================================================

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)
          // Convert date strings back to Date objects
          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 {
      // API call to save state
      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>
  )
}

// =============================================================================
// HOOK
// =============================================================================

export function useTOMGenerator(): TOMGeneratorContextValue {
  const context = useContext(TOMGeneratorContext)
  if (!context) {
    throw new Error(
      'useTOMGenerator must be used within a TOMGeneratorProvider'
    )
  }
  return context
}

// =============================================================================
// EXPORTS
// =============================================================================

export { TOMGeneratorContext }
export type { TOMGeneratorAction, TOMGeneratorContextValue }
