import type {
  VendorComplianceState,
  VendorComplianceAction,
  VendorStatistics,
  ComplianceStatistics,
  RiskOverview,
  VendorStatus,
  VendorRole,
  RiskLevel,
  FindingType,
  FindingSeverity,
} from './types'

import { getRiskLevelFromScore } from './types'

// ==========================================
// INITIAL STATE
// ==========================================

export const initialState: VendorComplianceState = {
  processingActivities: [],
  vendors: [],
  contracts: [],
  findings: [],
  controls: [],
  controlInstances: [],
  riskAssessments: [],
  isLoading: false,
  error: null,
  selectedVendorId: null,
  selectedActivityId: null,
  activeTab: 'overview',
  lastModified: null,
}

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

export function vendorComplianceReducer(
  state: VendorComplianceState,
  action: VendorComplianceAction
): VendorComplianceState {
  const updateState = (updates: Partial<VendorComplianceState>): VendorComplianceState => ({
    ...state,
    ...updates,
    lastModified: new Date(),
  })

  switch (action.type) {
    // Processing Activities
    case 'SET_PROCESSING_ACTIVITIES':
      return updateState({ processingActivities: action.payload })

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

    case 'UPDATE_PROCESSING_ACTIVITY':
      return updateState({
        processingActivities: state.processingActivities.map((activity) =>
          activity.id === action.payload.id
            ? { ...activity, ...action.payload.data, updatedAt: new Date() }
            : activity
        ),
      })

    case 'DELETE_PROCESSING_ACTIVITY':
      return updateState({
        processingActivities: state.processingActivities.filter(
          (activity) => activity.id !== action.payload
        ),
      })

    // Vendors
    case 'SET_VENDORS':
      return updateState({ vendors: action.payload })

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

    case 'UPDATE_VENDOR':
      return updateState({
        vendors: state.vendors.map((vendor) =>
          vendor.id === action.payload.id
            ? { ...vendor, ...action.payload.data, updatedAt: new Date() }
            : vendor
        ),
      })

    case 'DELETE_VENDOR':
      return updateState({
        vendors: state.vendors.filter((vendor) => vendor.id !== action.payload),
      })

    // Contracts
    case 'SET_CONTRACTS':
      return updateState({ contracts: action.payload })

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

    case 'UPDATE_CONTRACT':
      return updateState({
        contracts: state.contracts.map((contract) =>
          contract.id === action.payload.id
            ? { ...contract, ...action.payload.data, updatedAt: new Date() }
            : contract
        ),
      })

    case 'DELETE_CONTRACT':
      return updateState({
        contracts: state.contracts.filter((contract) => contract.id !== action.payload),
      })

    // Findings
    case 'SET_FINDINGS':
      return updateState({ findings: action.payload })

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

    case 'UPDATE_FINDING':
      return updateState({
        findings: state.findings.map((finding) =>
          finding.id === action.payload.id
            ? { ...finding, ...action.payload.data, updatedAt: new Date() }
            : finding
        ),
      })

    // Controls
    case 'SET_CONTROLS':
      return updateState({ controls: action.payload })

    case 'SET_CONTROL_INSTANCES':
      return updateState({ controlInstances: action.payload })

    case 'UPDATE_CONTROL_INSTANCE':
      return updateState({
        controlInstances: state.controlInstances.map((instance) =>
          instance.id === action.payload.id
            ? { ...instance, ...action.payload.data }
            : instance
        ),
      })

    // Risk Assessments
    case 'SET_RISK_ASSESSMENTS':
      return updateState({ riskAssessments: action.payload })

    case 'UPDATE_RISK_ASSESSMENT':
      return updateState({
        riskAssessments: state.riskAssessments.map((assessment) =>
          assessment.id === action.payload.id
            ? { ...assessment, ...action.payload.data }
            : assessment
        ),
      })

    // UI State
    case 'SET_LOADING':
      return { ...state, isLoading: action.payload }

    case 'SET_ERROR':
      return { ...state, error: action.payload }

    case 'SET_SELECTED_VENDOR':
      return { ...state, selectedVendorId: action.payload }

    case 'SET_SELECTED_ACTIVITY':
      return { ...state, selectedActivityId: action.payload }

    case 'SET_ACTIVE_TAB':
      return { ...state, activeTab: action.payload }

    default:
      return state
  }
}

// ==========================================
// COMPUTED VALUES (pure functions of state)
// ==========================================

export function computeVendorStats(state: VendorComplianceState): VendorStatistics {
  const vendors = state.vendors

  const byStatus = vendors.reduce(
    (acc, v) => {
      acc[v.status] = (acc[v.status] || 0) + 1
      return acc
    },
    {} as Record<VendorStatus, number>
  )

  const byRole = vendors.reduce(
    (acc, v) => {
      acc[v.role] = (acc[v.role] || 0) + 1
      return acc
    },
    {} as Record<VendorRole, number>
  )

  const byRiskLevel = vendors.reduce(
    (acc, v) => {
      const level = getRiskLevelFromScore(v.residualRiskScore / 4) // Normalize to 1-25
      acc[level] = (acc[level] || 0) + 1
      return acc
    },
    {} as Record<RiskLevel, number>
  )

  const now = new Date()
  const pendingReviews = vendors.filter(
    (v) => v.nextReviewDate && new Date(v.nextReviewDate) <= now
  ).length

  const withExpiredContracts = vendors.filter((v) =>
    state.contracts.some(
      (c) =>
        c.vendorId === v.id &&
        c.expirationDate &&
        new Date(c.expirationDate) <= now &&
        c.status === 'ACTIVE'
    )
  ).length

  return {
    total: vendors.length,
    byStatus,
    byRole,
    byRiskLevel,
    pendingReviews,
    withExpiredContracts,
  }
}

export function computeComplianceStats(state: VendorComplianceState): ComplianceStatistics {
  const findings = state.findings
  const contracts = state.contracts
  const controlInstances = state.controlInstances

  const averageComplianceScore =
    contracts.length > 0
      ? contracts.reduce((sum, c) => sum + (c.complianceScore || 0), 0) /
        contracts.filter((c) => c.complianceScore !== undefined).length || 0
      : 0

  const findingsByType = findings.reduce(
    (acc, f) => {
      acc[f.type] = (acc[f.type] || 0) + 1
      return acc
    },
    {} as Record<FindingType, number>
  )

  const findingsBySeverity = findings.reduce(
    (acc, f) => {
      acc[f.severity] = (acc[f.severity] || 0) + 1
      return acc
    },
    {} as Record<FindingSeverity, number>
  )

  const openFindings = findings.filter(
    (f) => f.status === 'OPEN' || f.status === 'IN_PROGRESS'
  ).length

  const resolvedFindings = findings.filter(
    (f) => f.status === 'RESOLVED' || f.status === 'FALSE_POSITIVE'
  ).length

  const passedControls = controlInstances.filter(
    (ci) => ci.status === 'PASS'
  ).length
  const applicableControls = controlInstances.filter(
    (ci) => ci.status !== 'NOT_APPLICABLE'
  ).length
  const controlPassRate =
    applicableControls > 0 ? (passedControls / applicableControls) * 100 : 0

  return {
    averageComplianceScore,
    findingsByType,
    findingsBySeverity,
    openFindings,
    resolvedFindings,
    controlPassRate,
  }
}

export function computeRiskOverview(state: VendorComplianceState): RiskOverview {
  const vendors = state.vendors
  const findings = state.findings

  const averageInherentRisk =
    vendors.length > 0
      ? vendors.reduce((sum, v) => sum + v.inherentRiskScore, 0) / vendors.length
      : 0

  const averageResidualRisk =
    vendors.length > 0
      ? vendors.reduce((sum, v) => sum + v.residualRiskScore, 0) / vendors.length
      : 0

  const highRiskVendors = vendors.filter(
    (v) => v.residualRiskScore >= 60
  ).length

  const criticalFindings = findings.filter(
    (f) => f.severity === 'CRITICAL' && f.status === 'OPEN'
  ).length

  const transfersToThirdCountries = vendors.filter((v) =>
    v.processingLocations.some((pl) => !pl.isEU && !pl.isAdequate)
  ).length

  return {
    averageInherentRisk,
    averageResidualRisk,
    highRiskVendors,
    criticalFindings,
    transfersToThirdCountries,
  }
}
