import React, {
  createContext,
  useContext, 
  useMemo,
  useState,
  useCallback,
  type ReactNode,
  useEffect,
} from 'react';
import { useFormik, type FormikProps } from 'formik';
import { cloneDeep } from 'lodash-es';
import * as Yup from 'yup';
import {
  type CurriculumReviewContents, 
} from '@/types/curriculumContents.type'; 
import type { Curriculum, ReviewQuestionElement } from '@/types/curriculum.type';

interface CurriculumReviewFormValues {
  answers: Record<string, string>;
}

interface CurriculumReviewContextValue {
  reviewContents: CurriculumReviewContents;
  formik: FormikProps<CurriculumReviewFormValues>;
  curriculum: Curriculum;
  sectionTitle: string | undefined;
  onClickEndReview: () => void;
  // step 관련 추가
  step: number;
  setStep: (step: number) => void;
  handleStart: () => void;
  handleNext: () => void;
  handlePrev: () => void;
  onClickReviewMyAnswer: () => void;
  handleSubmit: () => void;
  currentQuestion: ReviewQuestionElement | undefined;
  currentAnswer: string;
  currentError: string | undefined; 
  handleAnswerChange: (value: string) => void;
  done: boolean;
}

const CurriculumReviewContext = createContext<
  CurriculumReviewContextValue | undefined
>(undefined);

interface CurriculumReviewProviderProps extends Pick<CurriculumReviewContextValue, 'reviewContents' | 'sectionTitle' | 'onClickEndReview'  | 'curriculum' | 'done' > {
  children: ReactNode;
  /** 제출 후, 다음 학습으로 넘어가기 버튼 */
  onClickEndReview: () => void;
  /** key: 질문의 uuid, value: 응답 값 */
  onSubmit: (values: Record<string, string>) => Promise<boolean>;  
  /** key: 질문의 uuid, value: 응답 값 */
  defaultValues?: Record<string, string>; 
  onReviewValueChange: ({
    reviewId,
    answer,
  }: {
    reviewId: string;
    answer: Record<string, string>;
  }) => void;
  mode: 'edit' | 'create';
}

function getInitialAnswers(
  defaultValues: Record<string, string>,
  questions: ReviewQuestionElement[]
): Record<string, string> {
  return questions.reduce<Record<string, string>>((acc, q) => {
    acc[q.uuid] = defaultValues[q.uuid] ?? '';
    return acc;
  }, {});
}
 
function createAnswersYupSchema(
  questions: ReviewQuestionElement[]
): Yup.ObjectSchema<Record<string, string | undefined>> {
  const shape: Record<string, Yup.StringSchema> = {};
  questions.forEach((q) => {
    let schema = Yup.string();
    if (q.required) {
      schema = schema
        .required(`${q.title}은(는) 필수 입력 항목입니다.`)
        .trim();
      if (q.minLength && typeof q.minLength === 'number') {
        schema = schema.min(
          q.minLength,
          `${q.title}은(는) 최소 ${q.minLength}자 이상 입력해야 합니다.`
        );
      }
    } else {
      schema = schema.min(0);
    }
    shape[q.uuid] = schema;
  });
  return Yup.object().shape(shape);
} 

export function CurriculumReviewProvider({
  reviewContents: _reviewContents,
  sectionTitle,
  children,
  onClickEndReview, 
  onSubmit,
  defaultValues, 
  curriculum,
  onReviewValueChange,
  done,
}: CurriculumReviewProviderProps): React.ReactElement {
  
  const fixedReviewContents = useMemo<CurriculumReviewContents>(() => {
    const result = cloneDeep(_reviewContents);
    result.questions = result.questions.map((question) => {
      if (question.type === 'question_satisfaction_option') {
        return {
          ...curriculum.contents.satisfactionOptionMeta,
          ...question,
        };
      }
      if (question.type === 'question_satisfaction_text') {
        return {
          ...curriculum.contents.satisfactionTextMeta,
          ...question,
        };
      }
      return question;
    });
    return result;
  }, [
    curriculum.contents.satisfactionOptionMeta,
    curriculum.contents.satisfactionTextMeta,
    _reviewContents,
  ]);


  // step 상태 및 관련 로직 추가
  const [step, setStep] = useState<number>(0); // 0: 소개, 1~N: 질문, N+1: 완료

  // Yup 스키마 생성
  const answersYupSchema = useMemo(
    () => createAnswersYupSchema(fixedReviewContents.questions),
    [fixedReviewContents.questions]
  );

  const formik = useFormik<CurriculumReviewFormValues>({
    initialValues: {
      answers:  getInitialAnswers(defaultValues ?? {}, fixedReviewContents.questions),
    },
    validationSchema: Yup.object({
      answers: answersYupSchema,
    }),
    onSubmit: (values) => {
      
      const result = onSubmit(values.answers);
      return result.then((isSuccess: boolean) => {
        if (isSuccess) {
          setStep(prev => prev + 1);
        }
        return isSuccess;
      });
    },
    enableReinitialize: true,
    validateOnMount: true,
    validateOnChange: true,
  });

  // step 관련 핸들러 및 메모
  const questions = fixedReviewContents.questions;

  const handleStart = useCallback((): void => {
    setStep(1);
  }, []);

  const handleNext = useCallback((): void => {
    if (step < questions.length) {
      setStep(step + 1);
    } else {
      // 마지막 질문: 제출
      formik.handleSubmit();
      setStep(questions.length + 1);
    }
  }, [step, questions.length, formik]);

  const handlePrev = useCallback((): void => {
    if (step > 1) {
      setStep(step - 1);
    }
  }, [step]);

  const onClickReviewMyAnswer = useCallback((): void => {
    setStep(0);
  }, []);

  const handleSubmit = useCallback((): void => {
    formik.handleSubmit();
  }, [formik]);

  // 현재 질문 정보
  const currentQuestion = useMemo(() => {
    return step > 0 && step <= questions.length
      ? questions[step - 1]
      : undefined;
  }, [step, questions]);

  const currentAnswer = useMemo(() => {
    return currentQuestion ? formik.values.answers[currentQuestion.uuid] : '';
  }, [currentQuestion, formik.values.answers]);

  const currentError = useMemo(() => { 
    return (
      currentQuestion &&
      formik.errors.answers &&
      (formik.errors.answers as Record<string, string>)[currentQuestion.uuid]
    );
  }, [currentQuestion, formik.errors.answers]);
 
  const handleAnswerChange = useCallback(
    (value: string): void => {
      if (currentQuestion) {
        void formik.setFieldValue(`answers.${currentQuestion.uuid}`, value);
      }
    },
    [currentQuestion, formik]
  );

  useEffect(() => {
    if (currentQuestion) {
      onReviewValueChange({
        reviewId: currentQuestion.uuid,
        answer: formik.values.answers,
      });
    }
  // eslint-disable-next-line react-hooks/exhaustive-deps -- 트리거 최적화
  }, [currentQuestion?.uuid, currentAnswer, onReviewValueChange]);
 
  return (
    <CurriculumReviewContext.Provider
      value={{
        reviewContents: fixedReviewContents,
        formik,
        curriculum,
        sectionTitle,
        onClickEndReview, 
        step,
        setStep,
        handleStart,
        handleNext,
        handlePrev,
        onClickReviewMyAnswer,
        handleSubmit,
        currentQuestion,
        currentAnswer,
        currentError, 
        handleAnswerChange,
        done,
      }}
    >
      {children}
    </CurriculumReviewContext.Provider>
  );
}

export function useCurriculumReviewContext(): CurriculumReviewContextValue {
  const context = useContext(CurriculumReviewContext);
  if (!context) {
    throw new Error(
      'useCurriculumReviewContext must be used within a CurriculumReviewProvider'
    );
  }
  return context;
}
