import React, { createContext, useCallback, useContext, useEffect, useMemo, useState } from 'react';
import {
  DOCUMENT_VERSION,
  PICKUP_STATUS,
  STEP_NAMES,
  TOTAL_STEPS,
} from '../data/constants';
import {
  createInitialState,
  generatePickupCode,
  loadTrainingState,
  resetTrainingState,
  saveTrainingState,
} from '../data/storage';

const TrainingContext = createContext(null);

function isQualificationRequired(tonnage) {
  return tonnage > 18;
}

function getRequiredCertTypes(tonnage) {
  const base = ['idFront', 'idBack', 'licenseFront', 'licenseBack'];
  if (isQualificationRequired(tonnage)) base.push('qualification');
  return base;
}

export { isQualificationRequired, getRequiredCertTypes };

export function TrainingProvider({ children }) {
  const [state, setState] = useState(() => loadTrainingState());

  useEffect(() => {
    saveTrainingState(state);
  }, [state]);

  const updateState = useCallback((updater) => {
    setState((prev) => {
      const next = typeof updater === 'function' ? updater(prev) : { ...prev, ...updater };
      return next;
    });
  }, []);

  const invalidateAfterStep3 = useCallback((prev) => ({
    ...prev,
    step6: {
      signatureDataUrl: null,
      checked: false,
      submitted: false,
      submittedAt: null,
    },
    step7: {
      pickupCode: null,
      numericCode: null,
      status: PICKUP_STATUS.PENDING,
      generatedAt: null,
      completedAt: null,
      lockedAt: null,
    },
    maxCompletedStep: Math.min(prev.maxCompletedStep, 5),
    currentStep: Math.min(prev.currentStep, 6),
  }), []);

  const goToStep = useCallback((step) => {
    setState((prev) => {
      if (step > prev.maxCompletedStep + 1) return prev;
      return { ...prev, currentStep: step };
    });
  }, []);

  const completeStep = useCallback((step) => {
    setState((prev) => ({
      ...prev,
      maxCompletedStep: Math.max(prev.maxCompletedStep, step),
      currentStep: Math.min(step + 1, TOTAL_STEPS),
    }));
  }, []);

  const resetAll = useCallback(() => {
    const fresh = resetTrainingState();
    setState(fresh);
    return fresh;
  }, []);

  const applyDebugSettings = useCallback((debugPatch) => {
    setState((prev) => {
      let next = {
        ...prev,
        debug: { ...prev.debug, ...debugPatch },
      };

      if (debugPatch.vehicleTonnage !== undefined) {
        next.trainingTask = {
          ...next.trainingTask,
          vehicleTonnage: debugPatch.vehicleTonnage,
          vehicleType:
            debugPatch.vehicleTonnage >= 49
              ? '49吨氢能重卡'
              : debugPatch.vehicleTonnage >= 18
                ? '18吨氢能轻卡'
                : '4.5吨氢能物流车',
        };
        if (prev.step7.pickupCode) {
          next = invalidateAfterStep3(next);
          next.step7 = { ...next.step7, status: PICKUP_STATUS.REVOKED };
        }
      }

      if (debugPatch.pickupStatus !== undefined) {
        const statusMap = {
          pending: PICKUP_STATUS.PENDING,
          locked: PICKUP_STATUS.LOCKED,
          single_sign: PICKUP_STATUS.PROCESSING,
          both_signed: PICKUP_STATUS.COMPLETED,
          revoked: PICKUP_STATUS.REVOKED,
        };
        const status = statusMap[debugPatch.pickupStatus] || PICKUP_STATUS.PENDING;
        next.step7 = {
          ...next.step7,
          status,
          pickupCode: next.step7.pickupCode || `PK-${next.trainingTask.taskId}`,
          numericCode: next.step7.numericCode || generatePickupCode(),
          generatedAt: next.step7.generatedAt || new Date().toISOString(),
          lockedAt: status !== PICKUP_STATUS.PENDING ? new Date().toISOString() : null,
          completedAt: status === PICKUP_STATUS.COMPLETED ? new Date().toISOString() : null,
        };
        if (status === PICKUP_STATUS.COMPLETED || status === PICKUP_STATUS.REVOKED) {
          next.step7.status = status;
        }
      }

      if (debugPatch.videoStatus === 'completed') {
        next.step4 = {
          completed: true,
          watchedSeconds: 30,
          completedAt: new Date().toISOString(),
        };
      } else if (debugPatch.videoStatus === 'incomplete') {
        next.step4 = { completed: false, watchedSeconds: 0, completedAt: null };
        next.maxCompletedStep = Math.min(next.maxCompletedStep, 3);
      }

      return next;
    });
  }, [invalidateAfterStep3]);

  const updateCertificate = useCallback((certType, data) => {
    setState((prev) => {
      let next = {
        ...prev,
        step3: {
          ...prev.step3,
          certificates: {
            ...prev.step3.certificates,
            [certType]: { ...prev.step3.certificates[certType], ...data },
          },
        },
      };
      if (prev.step6.submitted || prev.step7.pickupCode) {
        next = invalidateAfterStep3(next);
      }
      return next;
    });
  }, [invalidateAfterStep3]);

  const submitTraining = useCallback(() => {
    setState((prev) => {
      const numericCode = generatePickupCode();
      const now = new Date().toISOString();
      return {
        ...prev,
        step6: {
          ...prev.step6,
          submitted: true,
          submittedAt: now,
        },
        step7: {
          pickupCode: `PK-${prev.trainingTask.taskId}-${numericCode}`,
          numericCode,
          status: PICKUP_STATUS.PENDING,
          generatedAt: now,
          completedAt: null,
          lockedAt: null,
        },
        maxCompletedStep: TOTAL_STEPS,
        currentStep: TOTAL_STEPS,
      };
    });
  }, []);

  const value = useMemo(
    () => ({
      state,
      updateState,
      goToStep,
      completeStep,
      resetAll,
      applyDebugSettings,
      updateCertificate,
      submitTraining,
      isQualificationRequired,
      getRequiredCertTypes,
      stepNames: STEP_NAMES,
      documentVersion: DOCUMENT_VERSION,
    }),
    [
      state,
      updateState,
      goToStep,
      completeStep,
      resetAll,
      applyDebugSettings,
      updateCertificate,
      submitTraining,
    ]
  );

  return <TrainingContext.Provider value={value}>{children}</TrainingContext.Provider>;
}

export function useTraining() {
  const ctx = useContext(TrainingContext);
  if (!ctx) throw new Error('useTraining must be used within TrainingProvider');
  return ctx;
}

export { createInitialState };
