import React, { memo, useCallback, useMemo, useRef, useState } from 'react';
import { __ } from '@wordpress/i18n';
import QuizQuestions from '../quizPages/QuizQuestions';
import { Formik, useFormikContext } from 'formik';
import { Box, Button, Flex } from '@chakra-ui/react';
import {
	DndContext,
	DragOverlay,
	PointerSensor,
	useSensor,
	useSensors,
} from '@dnd-kit/core';
import {
	SortableContext,
	verticalListSortingStrategy,
} from '@dnd-kit/sortable';
import OverlayQst from '../quizPages/OverlayQst';
import GstText from '@QPComponents/GstText.js';
import QuestionsHeader from '../stepsComponents/secondStep/QuestionsHeader';
import QuestionsFooter from '../stepsComponents/secondStep/QuestionsFooter';
import {
	createQuestion,
	updateQuestion,
} from '@QPRedux/Slices/quizQuestionSlice/quizQuestionSlice';
import {
	createAnswer,
	deleteAnswer,
	updateAnswer,
} from '@QPRedux/Slices/quizQuestionSlice/answerActions';
import { useDispatch, useSelector } from 'react-redux';
import { updateQuiz } from '@QPRedux/Slices/quizSlice/quizSlice';
import { primaryBtn } from '../../../../../../../assets/scss/chakra/recipe';
import {
	getInitialQuestionValue,
	getPaginatedItems,
	handleUpdateQuestionOrder,
	makeQstMeta,
	sortByOrder,
	toggleStore,
} from '../helper';
import _ from 'lodash';
import './styles/secondStep.scss';
import QuestionImport from '../quizPages/QuestionImport';

const SecondStep = () => {
	const settings = useSelector( ( state ) => state.settings );
	const { values: quizValues, setFieldValue: quizSaveHandler } =
		useFormikContext();

	const [ activeQst, setActiveQst ] = useState( null );
	const [ filterOpen, setFilterOpen ] = useState( false );
	const [ openImportModal, setOpenImportModal ] = useState( false );
	const [ isQuestionImportModalOpen, setIsQuestionImportModalOpen ] =
		useState( false );
	const [ currentPageNumber, setCurrentPageNumber ] = useState( 1 );
	const [ filteredQsts, setFilteredQsts ] = useState( null );
	const [ currentIndex, setCurrentIndex ] = useState( 0 );
	const formikStateRef = useRef( [] );

	const originalQsts = quizValues.questions || [];
	const displayedQsts = filteredQsts || originalQsts;
	const rowsPerPage = 10;

	const quizId = quizValues.id;

	const visibleQstsWithGlobalIndex = useMemo(
		() =>
			sortByOrder(
				getPaginatedItems(
					displayedQsts,
					currentPageNumber,
					rowsPerPage
				)
			).map( ( q ) => {
				const globalIndex = originalQsts.findIndex( ( oq ) =>
					_.isEqual( _.omit( oq, 'answers' ), _.omit( q, 'answers' ) )
				);
				return { ...q, _globalIndex: globalIndex };
			} ),
		[ displayedQsts, currentPageNumber, originalQsts ]
	);

	const dispatch = useDispatch();
	const sensors = useSensors(
		useSensor( PointerSensor, {
			activationConstraint: {
				distance: 5,
			},
		} )
	);

	const toggleOpen = useCallback(
		( val ) => {
			toggleStore.toggle( quizId, val );
		},
		[ quizId ]
	);

	const handleDragStart = ( { active } ) => {
		const foundQst = originalQsts.find(
			( _, i ) => `qst-${ i }` === active.id
		);
		if ( foundQst ) {
			setActiveQst( foundQst );
		}
	};

	const handleDragEnd = ( event ) => {
		const { active, over } = event;
		setActiveQst( null );

		if ( ! over || active.id === over.id ) {
			return;
		}

		const questions = [ ...quizValues.questions ];

		const oldIndex = questions.findIndex(
			( _, index ) => `qst-${ index }` === active.id
		);
		const newIndex = questions.findIndex(
			( _, index ) => `qst-${ index }` === over.id
		);

		if ( oldIndex === -1 || newIndex === -1 ) {
			return;
		}

		const [ movedItem ] = questions.splice( oldIndex, 1 );
		questions.splice( newIndex, 0, movedItem );

		const updatedQuestions = questions.map( ( q, i ) => ( {
			...q,
			question_order: i + 1,
		} ) );

		quizSaveHandler( 'questions', updatedQuestions );

		const newQstOrderPayload = updatedQuestions.map( ( q ) => ( {
			question_id: q.question_id,
			question_order: q.question_order,
		} ) );
		handleUpdateQuestionOrder( quizValues, newQstOrderPayload );

		if ( filteredQsts ) {
			setFilteredQsts( null );
		}
	};

	const updateQuestionInFormikState = useCallback(
		( updatedQuestion, finalAnswers, targetIndex, formikBag ) => {
			const finalQuestion = {
				...updatedQuestion,
				answers: finalAnswers,
			};

			let newQuestions = [ ...quizValues.questions ];

			newQuestions[ targetIndex ] = finalQuestion;

			newQuestions = newQuestions.map( ( qst, i ) => {
				const savedUnsaved = formikStateRef.current[ i ];
				return savedUnsaved ? _.merge( {}, savedUnsaved, qst ) : qst;
			} );

			const qstId = `qst-${ targetIndex }`;

			if ( toggleStore.isOpen( quizId, qstId ) ) {
				toggleOpen( qstId );
			}

			quizSaveHandler( 'questions', newQuestions );

			dispatch(
				updateQuiz( {
					params: {
						...quizValues,
						meta: {
							...quizValues.meta,
							quizpress_quiz_questions:
								makeQstMeta( newQuestions ),
						},
					},
					questions: newQuestions,
				} )
			);
		},
		[ quizValues, quizId, dispatch, toggleStore, toggleOpen ]
	);

	const handleAnswers = useCallback(
		async ( question_id, submittedAnswers ) => {
			const existingAnswers =
				quizValues.questions.find(
					( q ) => Number( q.question_id ) === Number( question_id )
				)?.answers || [];

			// Delete removed answers
			const deleteOps = existingAnswers
				.filter(
					( a ) =>
						! submittedAnswers.some(
							( sa ) =>
								Number( sa.answer_id ) === Number( a.answer_id )
						)
				)
				.map( ( a ) => dispatch( deleteAnswer( a.answer_id ) ) )
				.filter( Boolean );

			if ( deleteOps.length ) {
				await Promise.all( deleteOps );
			}

			// Create / Update answers
			const updateOps = submittedAnswers.map( ( ans ) => {
				const match = existingAnswers.find(
					( a ) => Number( a.answer_id ) === Number( ans.answer_id )
				);
				if ( _.isEqual( ans, match ) ) {
					return Promise.resolve( match );
				}
				const action = ans.answer_id ? updateAnswer : createAnswer;
				return dispatch( action( { ...ans, question_id } ) );
			} );

			const results = await Promise.all( updateOps );
			return results.map( ( r ) => r.payload || r );
		},
		[ quizValues.questions, dispatch ]
	);

	const handleQstSubmit = async ( values, formikBag ) => {
		formikBag.setSubmitting( true );
		try {
			const { answers, _globalIndex, ...questionData } = values;

			let finalQuestion, finalAnswers;

			if ( questionData?.question_id ) {
				finalAnswers = await handleAnswers(
					questionData.question_id,
					answers
				);

				const existingQuestion = ( quizValues?.questions || [] ).find(
					( q ) =>
						Number( q.question_id ) ===
						Number( questionData.question_id )
				);
				const isChanged = ! _.isEqual(
					questionData,
					_.omit( existingQuestion, 'answers' )
				);

				finalQuestion = isChanged
					? ( await dispatch( updateQuestion( questionData ) ) )
							.payload
					: existingQuestion;
			} else {
				const questionResult = await dispatch(
					createQuestion( questionData )
				);
				finalQuestion = questionResult.payload;

				finalAnswers = await handleAnswers(
					finalQuestion.question_id,
					answers
				);
			}
			if ( finalQuestion ) {
				updateQuestionInFormikState(
					finalQuestion,
					finalAnswers,
					_globalIndex,
					formikBag
				);
			}
		} catch ( error ) {
			console.error( 'Submission failed:', error );
		} finally {
			// setSubmitting(false);
		}
	};

	const handleAddQst = () => {
		quizSaveHandler( 'questions', [
			getInitialQuestionValue( settings, 1 ),
		] );
		setFilteredQsts( null );
		setCurrentIndex( 0 );
		toggleOpen( `qst-${ 0 }` );
	};

	const QuestionFormWrapper = memo( ( { question, index } ) => (
		<Formik
			initialValues={ question }
			enableReinitialize={ false }
			onSubmit={ handleQstSubmit }
		>
			{ ( { values } ) => {
				useMemo( () => {
					if ( values?.question_id ) {
						return;
					}
					formikStateRef.current[ index ] = values;
				}, [ values ] );

				return (
					<QuizQuestions
						question={ question }
						setCurrentIndex={ setCurrentIndex }
						toggleOpen={ toggleOpen }
						index={ index }
						quizValues={ quizValues }
						quizSaveHandler={ quizSaveHandler }
					/>
				);
			} }
		</Formik>
	) );

	const commonProps = {
		originalQsts,
		rowsPerPage,
		setFilteredQsts,
		setCurrentIndex,
		toggleOpen,
		setOpenImportModal,
		setCurrentPageNumber,
	};

	const footerProps = {
		...commonProps,
		openImportModal,
		currentPageNumber,
		setIsQuestionImportModalOpen,
	};

	const headerProps = {
		...commonProps,
		filterOpen,
		setFilterOpen,
		currentPageNumber,
		setIsQuestionImportModalOpen,
	};

	return (
		<Flex
			direction="column"
			w="full"
			marginTop={ currentIndex === 0 ? '100px auto' : '24px auto' }
			gap={ 6 }
			className="quizpress-page-content"
		>
			<QuestionsHeader { ...headerProps } />

			{ ! displayedQsts.length && (
				<GstText
					label={ __( 'No Question Found', 'quizpress' ) }
					showBorder={ true }
					subtitle={ __(
						'Create your question set for this quiz',
						'quizpress'
					) }
					button={
						<Button { ...primaryBtn } onClick={ handleAddQst }>
							<span className="quizpress-icon quizpress-icon--plus has-quizpress-blue-bg" />
							{ __( 'Add Question', 'quizpress' ) }
						</Button>
					}
				/>
			) }

			<DndContext
				sensors={ sensors }
				onDragStart={ handleDragStart }
				onDragEnd={ ( event ) => handleDragEnd( event ) }
			>
				<SortableContext
					items={ originalQsts?.map(
						( _, index ) => `qst-${ index }`
					) }
					strategy={ verticalListSortingStrategy }
				>
					{ visibleQstsWithGlobalIndex.map( ( question ) => (
						<QuestionFormWrapper
							key={
								question?.question_id ?? question._globalIndex
							}
							index={ question._globalIndex }
							question={ question }
						/>
					) ) }
				</SortableContext>

				<DragOverlay>
					{ activeQst ? (
						<Box
							transform="rotate(1deg)"
							opacity={ 0.7 }
							pointerEvents="none"
						>
							<OverlayQst question={ activeQst } />
						</Box>
					) : null }
				</DragOverlay>
			</DndContext>
			<QuestionsFooter { ...footerProps } />

			{ isQuestionImportModalOpen && (
				<QuestionImport
					isOpen={ isQuestionImportModalOpen }
					onRequestClose={ () =>
						setIsQuestionImportModalOpen( false )
					}
				/>
			) }
		</Flex>
	);
};

export default SecondStep;
