'use client'

import React, {
  createContext,
  useContext,
  useReducer,
  useCallback,
  useMemo,
  useEffect,
  useState,
} from 'react'

import type {
  VendorComplianceContextValue,
  ProcessingActivity,
  Vendor,
  ContractDocument,
  Finding,
  ControlInstance,
  ExportFormat,
} from './types'

import {
  vendorComplianceReducer,
  initialState,
  computeVendorStats,
  computeComplianceStats,
  computeRiskOverview,
} from './context-reducer'

import {
  loadAllData,
  apiCreateProcessingActivity,
  apiUpdateProcessingActivity,
  apiDeleteProcessingActivity,
  apiDuplicateProcessingActivity,
  apiCreateVendor,
  apiUpdateVendor,
  apiDeleteVendor,
  apiUploadContract,
  apiUpdateContract,
  apiDeleteContract,
  apiStartContractReview,
  apiUpdateFinding,
  apiResolveFinding,
  apiUpdateControlInstance,
  apiExportVVT,
  apiExportVendorAuditPack,
  apiExportRoPA,
} from './context-actions'

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

const VendorComplianceContext = createContext<VendorComplianceContextValue | null>(null)

// ==========================================
// PROVIDER
// ==========================================

interface VendorComplianceProviderProps {
  children: React.ReactNode
  tenantId?: string
}

export function VendorComplianceProvider({
  children,
  tenantId,
}: VendorComplianceProviderProps) {
  const [state, dispatch] = useReducer(vendorComplianceReducer, initialState)
  const [isInitialized, setIsInitialized] = useState(false)

  // ==========================================
  // COMPUTED VALUES
  // ==========================================

  const vendorStats = useMemo(
    () => computeVendorStats(state),
    [state.vendors, state.contracts]
  )

  const complianceStats = useMemo(
    () => computeComplianceStats(state),
    [state.findings, state.contracts, state.controlInstances]
  )

  const riskOverview = useMemo(
    () => computeRiskOverview(state),
    [state.vendors, state.findings]
  )

  // ==========================================
  // ACTION WRAPPERS
  // ==========================================

  const loadData = useCallback(async () => {
    await loadAllData(dispatch)
  }, [])

  const refresh = useCallback(async () => {
    await loadData()
  }, [loadData])

  const createProcessingActivity = useCallback(
    async (data: Omit<ProcessingActivity, 'id' | 'tenantId' | 'createdAt' | 'updatedAt'>) => {
      return apiCreateProcessingActivity(dispatch, data)
    },
    []
  )

  const updateProcessingActivity = useCallback(
    async (id: string, data: Partial<ProcessingActivity>) => {
      await apiUpdateProcessingActivity(dispatch, id, data)
    },
    []
  )

  const deleteProcessingActivity = useCallback(
    async (id: string) => {
      await apiDeleteProcessingActivity(dispatch, id)
    },
    []
  )

  const duplicateProcessingActivity = useCallback(
    async (id: string) => {
      return apiDuplicateProcessingActivity(dispatch, state, id)
    },
    [state]
  )

  const createVendor = useCallback(
    async (data: Omit<Vendor, 'id' | 'tenantId' | 'createdAt' | 'updatedAt'>) => {
      return apiCreateVendor(dispatch, data)
    },
    []
  )

  const updateVendor = useCallback(
    async (id: string, data: Partial<Vendor>) => {
      await apiUpdateVendor(dispatch, id, data)
    },
    []
  )

  const deleteVendor = useCallback(
    async (id: string) => {
      await apiDeleteVendor(dispatch, id)
    },
    []
  )

  const uploadContract = useCallback(
    async (vendorId: string, file: File, metadata: Partial<ContractDocument>) => {
      return apiUploadContract(dispatch, state, vendorId, file, metadata)
    },
    [state]
  )

  const updateContract = useCallback(
    async (id: string, data: Partial<ContractDocument>) => {
      await apiUpdateContract(dispatch, id, data)
    },
    []
  )

  const deleteContract = useCallback(
    async (id: string) => {
      await apiDeleteContract(dispatch, state, id)
    },
    [state]
  )

  const startContractReview = useCallback(
    async (contractId: string) => {
      await apiStartContractReview(dispatch, contractId)
    },
    []
  )

  const updateFinding = useCallback(
    async (id: string, data: Partial<Finding>) => {
      await apiUpdateFinding(dispatch, id, data)
    },
    []
  )

  const resolveFinding = useCallback(
    async (id: string, resolution: string) => {
      await apiResolveFinding(dispatch, id, resolution)
    },
    []
  )

  const updateControlInstance = useCallback(
    async (id: string, data: Partial<ControlInstance>) => {
      await apiUpdateControlInstance(dispatch, id, data)
    },
    []
  )

  const exportVVT = useCallback(
    async (format: ExportFormat, activityIds?: string[]) => {
      return apiExportVVT(format, activityIds)
    },
    []
  )

  const exportVendorAuditPack = useCallback(
    async (vendorId: string, format: ExportFormat) => {
      return apiExportVendorAuditPack(vendorId, format)
    },
    []
  )

  const exportRoPA = useCallback(
    async (format: ExportFormat) => {
      return apiExportRoPA(format)
    },
    []
  )

  // ==========================================
  // INITIALIZATION
  // ==========================================

  useEffect(() => {
    if (!isInitialized) {
      loadData()
      setIsInitialized(true)
    }
  }, [isInitialized, loadData])

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

  const contextValue = useMemo<VendorComplianceContextValue>(
    () => ({
      ...state,
      dispatch,
      vendorStats,
      complianceStats,
      riskOverview,
      createProcessingActivity,
      updateProcessingActivity,
      deleteProcessingActivity,
      duplicateProcessingActivity,
      createVendor,
      updateVendor,
      deleteVendor,
      uploadContract,
      updateContract,
      deleteContract,
      startContractReview,
      updateFinding,
      resolveFinding,
      updateControlInstance,
      exportVVT,
      exportVendorAuditPack,
      exportRoPA,
      loadData,
      refresh,
    }),
    [
      state,
      vendorStats,
      complianceStats,
      riskOverview,
      createProcessingActivity,
      updateProcessingActivity,
      deleteProcessingActivity,
      duplicateProcessingActivity,
      createVendor,
      updateVendor,
      deleteVendor,
      uploadContract,
      updateContract,
      deleteContract,
      startContractReview,
      updateFinding,
      resolveFinding,
      updateControlInstance,
      exportVVT,
      exportVendorAuditPack,
      exportRoPA,
      loadData,
      refresh,
    ]
  )

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

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

export function useVendorCompliance(): VendorComplianceContextValue {
  const context = useContext(VendorComplianceContext)

  if (!context) {
    throw new Error(
      'useVendorCompliance must be used within a VendorComplianceProvider'
    )
  }

  return context
}

// ==========================================
// SELECTORS
// ==========================================

export function useVendor(vendorId: string | null) {
  const { vendors } = useVendorCompliance()
  return useMemo(
    () => vendors.find((v) => v.id === vendorId) ?? null,
    [vendors, vendorId]
  )
}

export function useProcessingActivity(activityId: string | null) {
  const { processingActivities } = useVendorCompliance()
  return useMemo(
    () => processingActivities.find((a) => a.id === activityId) ?? null,
    [processingActivities, activityId]
  )
}

export function useVendorContracts(vendorId: string | null) {
  const { contracts } = useVendorCompliance()
  return useMemo(
    () => contracts.filter((c) => c.vendorId === vendorId),
    [contracts, vendorId]
  )
}

export function useVendorFindings(vendorId: string | null) {
  const { findings } = useVendorCompliance()
  return useMemo(
    () => findings.filter((f) => f.vendorId === vendorId),
    [findings, vendorId]
  )
}

export function useContractFindings(contractId: string | null) {
  const { findings } = useVendorCompliance()
  return useMemo(
    () => findings.filter((f) => f.contractId === contractId),
    [findings, contractId]
  )
}

export function useControlInstancesForEntity(
  entityType: 'VENDOR' | 'PROCESSING_ACTIVITY',
  entityId: string | null
) {
  const { controlInstances, controls } = useVendorCompliance()

  return useMemo(() => {
    if (!entityId) return []

    return controlInstances
      .filter((ci) => ci.entityType === entityType && ci.entityId === entityId)
      .map((ci) => ({
        ...ci,
        control: controls.find((c) => c.id === ci.controlId),
      }))
  }, [controlInstances, controls, entityType, entityId])
}
