import React, {
  createContext,
  useContext,
  useState,
  useMemo,
  useCallback,
  useRef,
  useEffect,
} from 'react';
import {  
  type CurriculumSectionTitleContents,
} from '@/types/curriculumContents.type';
import type { Curriculum, CurriculumListContents } from '@/types/curriculum.type';


export interface CurriculumContextValue {
  curriculum: Curriculum;
  selectedIndex: number;
  setSelectedIndex: (idx: number) => void;
  selectedId: string;
  hasPrev: boolean;
  hasNext: boolean;
  selectPrev: (cb?: (moveIndex: number) => void) => void;
  selectNext: (cb?: (moveIndex: number) => void) => void;
  selectedItem: CurriculumListContents;
  /** 선택된 아이템의 이전 아이템 중 가장 가까운 섹션 타이틀 */
  selectedSectionTitle: CurriculumSectionTitleContents | null;
  /** 컨텐츠 목록 스크롤 이동 함수 */
  scrollNavItem: (uuid: string) => void;
  /** 스크롤 영역 참조 */
  scrollAreaRef: React.RefObject<HTMLDivElement | null>;
  /** 리뷰 제출 함수 */
  onReviewSubmit: ({
    reviewId,
    answer,
  }: {
    reviewId: string;
    answer: Record<string, string>;
  }) => Promise<boolean>;
  /** 리뷰 응답 값 변경 시 호출 */
  onReviewValueChange: ({
    reviewId,
    answer,
  }: {
    reviewId: string;
    answer: Record<string, string>;
  }) => void;
  /** 과제 완료 후 저장된 값 */
  curriculumReviewAnswers: Record<string, string>;
  /** 과제 완료 전 임시 저장된 값 */
  tempCurriculumReviewAnswers: Record<string, string>; 
  /** 항목 수강 완료 여부 */
  curriculumCompleteMap: Record<string, boolean>;
  /** action Button 클릭시 호출 */
  onActionButtonClick: (item: CurriculumListContents) => void;
  /** 초기 선택 인덱스 */
  initialSelectedIndex?: number;
}

const CurriculumContext = createContext<CurriculumContextValue | undefined>(
  undefined
);

export interface CurriculumProviderProps extends Pick<CurriculumContextValue, 'curriculum' | 'onReviewSubmit' | 'onReviewValueChange' | 'curriculumReviewAnswers' | 'tempCurriculumReviewAnswers' | 'curriculumCompleteMap' | 'onActionButtonClick' | 'initialSelectedIndex'> {
  children: React.ReactNode; 
  onReviewValueChange: ({
    reviewId,
    answer,
  }: {
    reviewId: string;
    answer: Record<string, string>;
  }) => void; 

  /** 현재 화면에 표시 중인 컨텐츠 인덱스 변경 시 호출 */
  onChangeSelectedContent?: (item: CurriculumListContents) => void;
}

export function CurriculumProvider(props: CurriculumProviderProps): React.ReactElement {
  const {
    children,
    curriculum,
    onReviewSubmit, 
    onReviewValueChange,
    curriculumReviewAnswers,
    tempCurriculumReviewAnswers, 
    curriculumCompleteMap,
    onChangeSelectedContent,
    onActionButtonClick,
    initialSelectedIndex
  } = props;
  const sidebarRef = useRef<HTMLDivElement>(null);

  const scrollNavItem = useCallback((index: string) => {
    const element = sidebarRef.current?.querySelector(
      `[data-curriculum-item-index="${index}"]`
    );
    if (element) {
      element.scrollIntoView({ behavior: 'smooth', block: 'start' });
    }
  }, []);

  const list = curriculum.contents.list;
  // 선택 가능한 인덱스만 추출
  const selectableIndexes = useMemo(
    () =>
      list
        .map((item, i) => (item.type !== 'sectionTitle' ? i : null))
        .filter((i): i is number => i !== null),
    [list]
  );
  // 최초 선택값: 첫 번째 선택 가능한 인덱스
  const [selectedIndexState, setSelectedIndexState] = useState<number>(
    initialSelectedIndex ?? selectableIndexes[0]
  );

  // 선택 인덱스 보정 함수
  const setSelectedIndex = useCallback(
    (idx: number) => {
      if (selectableIndexes.includes(idx)) {
        setSelectedIndexState(idx);
      } else {
        // idx가 선택 불가면, selectableIndexes에서 가장 가까운 다음 인덱스 선택
        const next = selectableIndexes.find((i) => i > idx);
        const prev = [...selectableIndexes].reverse().find((i) => i < idx);
        if (next !== undefined) setSelectedIndexState(next);
        else if (prev !== undefined) setSelectedIndexState(prev);
      }
    },
    [selectableIndexes]
  );

  // 현재 선택 인덱스가 selectableIndexes 내 몇 번째인지
  const selectablePos = useMemo(
    () => selectableIndexes.indexOf(selectedIndexState),
    [selectableIndexes, selectedIndexState]
  );
  const hasPrev = selectablePos > 0;
  const hasNext = selectablePos < selectableIndexes.length - 1;

  const selectPrev = useCallback(
    (cb?: (moveIndex: number) => void) => {
      setSelectedIndexState((cur) => {
        let prevIndex = cur;
        const pos = selectableIndexes.indexOf(cur);
        if (pos > 0) {
          prevIndex = selectableIndexes[pos - 1];
        }
        if (cb) cb(prevIndex);
        return prevIndex;
      });
    },
    [selectableIndexes]
  );
  const selectNext = useCallback(
    (cb?: (moveIndex: number) => void) => {
      setSelectedIndexState((cur) => {
        let nextIndex = cur;
        const pos = selectableIndexes.indexOf(cur);
        if (pos < selectableIndexes.length - 1) {
          nextIndex = selectableIndexes[pos + 1];
        }
        if (cb) cb(nextIndex);
        return nextIndex;
      });
    },
    [selectableIndexes]
  );

  const selectedId = useMemo(
    () => list[selectedIndexState]?.uuid ?? '',
    [list, selectedIndexState]
  );

  const selectedItem = useMemo(()=>{
    return list[selectedIndexState];
  },[list,selectedIndexState])

  const selectedSectionTitle = useMemo(() => {
    // selectedIndexState 이전 인덱스 중 가장 가까운 섹션 타이틀 찾기
    const prevItems = list.slice(0, selectedIndexState).reverse();
    return prevItems.find((item) => item.type === 'sectionTitle') ?? null;
  }, [list, selectedIndexState]);
 

  useEffect(()=>{ 
    onChangeSelectedContent?.(selectedItem);
  // eslint-disable-next-line react-hooks/exhaustive-deps -- 트리거 최소화
  },[selectedItem])

  return (
    <CurriculumContext.Provider value={{
      curriculum,
      scrollNavItem,
      selectedIndex: selectedIndexState,
      setSelectedIndex,
      selectedId,
      hasPrev,
      hasNext,
      selectPrev,
      selectNext,
      selectedSectionTitle,
      selectedItem,
      scrollAreaRef: sidebarRef,
      onReviewSubmit, 
      onReviewValueChange,
      curriculumReviewAnswers,
      tempCurriculumReviewAnswers, 
      curriculumCompleteMap,
      onActionButtonClick
    }}>
      {children}
    </CurriculumContext.Provider>
  );
}

export function useCurriculumContext(): CurriculumContextValue {
  const ctx = useContext(CurriculumContext);
  if (!ctx)
    throw new Error(
      'useCurriculumContext must be used within CurriculumProvider'
    );
  return ctx;
}
