import { useMemo, useState } from 'react';
import { useMutation, useQuery, useQueryClient } from '@tanstack/react-query';
import {
  createSafetyQuizResult,
  getMySafetyQuizStatus,
  getSafetyQuizCompletionReport,
  listSafetyQuizResults,
} from '@/shared/api/safetyQuizResults';
import {
  createManagedContentCatalog,
  deleteManagedContentCatalog,
  getManagedContentCatalog,
  updateManagedContentCatalog,
} from '@/shared/api/contentCatalog';
import { useContentCatalogPayload } from '@/business/content-catalog/hooks';
import {
  SAFETY_QUIZ_COMPLIANCE_QUERY_SEGMENT,
  SAFETY_QUIZ_QUERY_KEYS,
} from '@/shared/constants/safetyQuiz';
import {
  CONTENT_CATALOG_QUERY_KEYS,
  CONTENT_CATALOG_TYPES,
} from '@/shared/constants/contentCatalog';
import {
  toSafetyQuizCompletionRow,
  toSafetyQuizResultCreateDto,
} from '@/business/safety-quiz/mappers';
import {
  SafetyQuizContentEditor,
  SafetyQuizPage,
  SafetyQuizSubmission,
} from '@/business/safety-quiz/types';
import {
  calculateSafetyQuizCompletionSummary,
  calculateSafetyQuizScore,
  getCurrentSafetyQuizWeek,
  validateSafetyQuizPayload,
} from '@/business/safety-quiz/selectors';
import { canPersistPersonalScopeResults } from '@/business/scope/selectors';
import type { QuizQuestion, SafetyQuiz } from '@/shared/types/app';
import { getApiListRows } from '@/shared/business/apiListRows';
import { useInvalidatingMutation } from '@/shared/business/queryMutations';
import { getOptionalErrorMessage } from '@/shared/errors/errorMessages';
import { usePermissions } from '@/shared/app/usePermissions';
import { useScopeContext } from '@/shared/app/scope-context';

export function useSafetyQuizResults(weekOf?: string) {
  return useQuery({
    queryKey: weekOf ? [...SAFETY_QUIZ_QUERY_KEYS.results, weekOf] : SAFETY_QUIZ_QUERY_KEYS.results,
    queryFn: () => getApiListRows(listSafetyQuizResults(weekOf)),
  });
}

export function useMySafetyQuizStatus(weekOf?: string, enabled = true) {
  return useQuery({
    queryKey: weekOf
      ? [...SAFETY_QUIZ_QUERY_KEYS.personalStatus, weekOf]
      : SAFETY_QUIZ_QUERY_KEYS.personalStatus,
    enabled,
    queryFn: () => getMySafetyQuizStatus(weekOf),
  });
}

export function useSafetyQuizCompliance(weekOf: string, enabled: boolean) {
  return useQuery({
    queryKey: [...SAFETY_QUIZ_QUERY_KEYS.completion, SAFETY_QUIZ_COMPLIANCE_QUERY_SEGMENT, weekOf],
    enabled,
    queryFn: async () => {
      const report = await getSafetyQuizCompletionReport(weekOf);
      return {
        rows: report.rows.map(toSafetyQuizCompletionRow),
        summary: report.summary,
      };
    },
  });
}

export function useSaveSafetyQuizResult() {
  const queryClient = useQueryClient();

  return useInvalidatingMutation({
    mutationFn: (submission: SafetyQuizSubmission) => createSafetyQuizResult(
      toSafetyQuizResultCreateDto(submission),
    ),
    invalidateQueryKey: SAFETY_QUIZ_QUERY_KEYS.results,
    onSuccess: async (_data, submission) => {
      await Promise.all([
        queryClient.invalidateQueries({ queryKey: SAFETY_QUIZ_QUERY_KEYS.results }),
        queryClient.invalidateQueries({ queryKey: SAFETY_QUIZ_QUERY_KEYS.personalStatus }),
        queryClient.invalidateQueries({ queryKey: SAFETY_QUIZ_QUERY_KEYS.completion }),
        queryClient.invalidateQueries({
          queryKey: [...SAFETY_QUIZ_QUERY_KEYS.personalStatus, submission.weekOf],
        }),
        queryClient.invalidateQueries({
          queryKey: [...SAFETY_QUIZ_QUERY_KEYS.completion, SAFETY_QUIZ_COMPLIANCE_QUERY_SEGMENT, submission.weekOf],
        }),
      ]);
    },
  });
}

export function useSafetyQuizPage(): SafetyQuizPage {
  const permissions = usePermissions();
  const { ownTenant, selectedTenant } = useScopeContext();
  const activeTenant = selectedTenant ?? ownTenant;
  const canPersistResult = canPersistPersonalScopeResults(ownTenant, selectedTenant)
    && activeTenant?.level !== 'organization';
  const quizQuery = useContentCatalogPayload<SafetyQuiz | null>(
    CONTENT_CATALOG_TYPES.safetyQbsQuiz,
    null,
  );
  const [quizStarted, setQuizStarted] = useState(false);
  const [currentQuestionIndex, setCurrentQuestionIndex] = useState(0);
  const [selectedAnswer, setSelectedAnswer] = useState<number | null>(null);
  const [showExplanation, setShowExplanation] = useState(false);
  const [score, setScore] = useState(0);
  const [quizComplete, setQuizComplete] = useState(false);
  const [answers, setAnswers] = useState<readonly number[]>([]);
  const quiz = quizQuery.payload;
  const weekOf = getCurrentSafetyQuizWeek(new Date());
  const canViewCompliance = permissions.has('READ_SAFETY_QUIZ_REPORTS');
  const canManageQuizContent = permissions.has('MANAGE_CONTENT_CATALOG')
    && ownTenant?.level === 'organization'
    && activeTenant?.level === 'organization';
  const complianceQuery = useSafetyQuizCompliance(weekOf, canViewCompliance);
  const saveResultMutation = useSaveSafetyQuizResult();
  const complianceRows = complianceQuery.data?.rows ?? [];
  const completionSummary = complianceQuery.data?.summary ?? calculateSafetyQuizCompletionSummary(complianceRows);

  function startQuiz() {
    setQuizStarted(true);
  }

  function selectAnswer(answerIndex: number) {
    const question = quiz?.questions[currentQuestionIndex];

    if (showExplanation || !question) {
      return;
    }

    setSelectedAnswer(answerIndex);
    setShowExplanation(true);

    if (answerIndex === question.correctIndex) {
      setScore((currentScore) => currentScore + 1);
    }
  }

  async function goToNextQuestion() {
    if (selectedAnswer === null || !quiz) {
      return;
    }

    const nextAnswers = [...answers, selectedAnswer];

    if (currentQuestionIndex < quiz.questions.length - 1) {
      setAnswers(nextAnswers);
      setCurrentQuestionIndex((current) => current + 1);
      setSelectedAnswer(null);
      setShowExplanation(false);
      return;
    }

    const finalScore = calculateSafetyQuizScore(quiz, nextAnswers);
    setQuizComplete(true);
    setAnswers(nextAnswers);
    setScore(finalScore);
    if (canPersistResult) {
      await saveResultMutation.mutateAsync({
        quizId: quiz.id,
        quizTitle: quiz.title,
        score: finalScore,
        totalQuestions: quiz.questions.length,
        answers: nextAnswers,
        weekOf,
      });
    }
  }

  function resetQuiz() {
    setQuizStarted(false);
    setCurrentQuestionIndex(0);
    setSelectedAnswer(null);
    setShowExplanation(false);
    setScore(0);
    setQuizComplete(false);
    setAnswers([]);
  }

  return {
    quiz,
    weekOf,
    stage: quizComplete ? 'complete' : quizStarted ? 'question' : 'intro',
    currentQuestionIndex,
    selectedAnswer,
    showExplanation,
    score,
    answers,
    complianceRows,
    completionSummary,
    canViewCompliance,
    canManageQuizContent,
    canPersistResult,
    isQuizLoading: quizQuery.isLoading,
    isComplianceLoading: complianceQuery.isLoading,
    isSavingResult: saveResultMutation.isPending,
    quizError: quizQuery.error,
    complianceError: complianceQuery.error,
    saveResultError: saveResultMutation.error,
    startQuiz,
    selectAnswer,
    goToNextQuestion,
    resetQuiz,
  };
}

export function useSafetyQuizContentEditor(): SafetyQuizContentEditor {
  const queryClient = useQueryClient();
  const [draftOverride, setDraftOverride] = useState<SafetyQuiz | null>(null);
  const [hasDraftOverride, setHasDraftOverride] = useState(false);
  const [validationError, setValidationError] = useState<string | null>(null);
  const [savedMessage, setSavedMessage] = useState<string | null>(null);
  const contentType = CONTENT_CATALOG_TYPES.safetyQbsQuiz;
  const managedQuery = useQuery({
    queryKey: [...CONTENT_CATALOG_QUERY_KEYS.content, 'managed', contentType],
    queryFn: () => getManagedContentCatalog<SafetyQuiz>(contentType),
  });
  const saveMutation = useMutation({
    mutationFn: (payload: SafetyQuiz) => (
      managedQuery.data
        ? updateManagedContentCatalog(contentType, { payload })
        : createManagedContentCatalog({ content_type: contentType, payload })
    ),
    onSuccess: async (response) => {
      setDraftOverride(response.payload);
      setHasDraftOverride(true);
      setValidationError(null);
      setSavedMessage('Safety quiz content saved.');
      await Promise.all([
        queryClient.invalidateQueries({ queryKey: [...CONTENT_CATALOG_QUERY_KEYS.content, contentType] }),
        queryClient.invalidateQueries({ queryKey: [...CONTENT_CATALOG_QUERY_KEYS.content, 'managed', contentType] }),
      ]);
    },
  });
  const deleteMutation = useMutation({
    mutationFn: () => deleteManagedContentCatalog(contentType),
    onSuccess: async () => {
      setDraftOverride(null);
      setHasDraftOverride(true);
      setValidationError(null);
      setSavedMessage('Safety quiz content deleted.');
      await Promise.all([
        queryClient.invalidateQueries({ queryKey: [...CONTENT_CATALOG_QUERY_KEYS.content, contentType] }),
        queryClient.invalidateQueries({ queryKey: [...CONTENT_CATALOG_QUERY_KEYS.content, 'managed', contentType] }),
      ]);
    },
  });
  const serverDraft = useMemo(
    () => managedQuery.data?.payload ?? null,
    [managedQuery.data],
  );
  const draft = hasDraftOverride ? draftOverride : serverDraft;

  const canSave = useMemo(
    () => Boolean(draft) && !managedQuery.isLoading && !saveMutation.isPending && !deleteMutation.isPending,
    [draft, managedQuery.isLoading, saveMutation.isPending, deleteMutation.isPending],
  );

  function updateDraft(updater: (current: SafetyQuiz) => SafetyQuiz): void {
    setDraftOverride((currentOverride) => {
      const current = hasDraftOverride ? currentOverride : serverDraft;
      return current ? updater(current) : current;
    });
    setHasDraftOverride(true);
    setValidationError(null);
    setSavedMessage(null);
  }

  return {
    draft,
    isLoading: managedQuery.isLoading,
    isSaving: saveMutation.isPending,
    isDeleting: deleteMutation.isPending,
    errorMessage: getOptionalErrorMessage(
      managedQuery.error || saveMutation.error || deleteMutation.error,
      'Safety quiz content could not be loaded or saved.',
    ),
    validationError,
    savedMessage,
    canSave,
    updateQuiz: (patch) => updateDraft((current) => ({ ...current, ...patch })),
    updateWeeklyFocus: (patch) => updateDraft((current) => ({
      ...current,
      weeklyFocus: { ...current.weeklyFocus, ...patch },
    })),
    updateReminder: (index, value) => updateDraft((current) => ({
      ...current,
      keyReminders: current.keyReminders.map((reminder, reminderIndex) =>
        reminderIndex === index ? value : reminder,
      ),
    })),
    addReminder: () => updateDraft((current) => ({
      ...current,
      keyReminders: [...current.keyReminders, ''],
    })),
    removeReminder: (index) => updateDraft((current) => ({
      ...current,
      keyReminders: current.keyReminders.filter((_reminder, reminderIndex) => reminderIndex !== index),
    })),
    updateQuestion: (index, patch) => updateDraft((current) => ({
      ...current,
      questions: current.questions.map((question, questionIndex) =>
        questionIndex === index ? normalizeQuestion({ ...question, ...patch }) : question,
      ),
    })),
    updateQuestionOption: (questionIndex, optionIndex, value) => updateDraft((current) => ({
      ...current,
      questions: current.questions.map((question, currentQuestionIndex) => {
        if (currentQuestionIndex !== questionIndex) {
          return question;
        }
        return normalizeQuestion({
          ...question,
          options: question.options.map((option, currentOptionIndex) =>
            currentOptionIndex === optionIndex ? value : option,
          ),
        });
      }),
    })),
    addQuestion: () => updateDraft((current) => ({
      ...current,
      questions: [...current.questions, createDefaultQuestion(current.questions.length + 1)],
    })),
    removeQuestion: (index) => updateDraft((current) => ({
      ...current,
      questions: current.questions.filter((_question, questionIndex) => questionIndex !== index),
    })),
    addQuestionOption: (questionIndex) => updateDraft((current) => ({
      ...current,
      questions: current.questions.map((question, currentQuestionIndex) =>
        currentQuestionIndex === questionIndex
          ? normalizeQuestion({ ...question, options: [...question.options, ''] })
          : question,
      ),
    })),
    removeQuestionOption: (questionIndex, optionIndex) => updateDraft((current) => ({
      ...current,
      questions: current.questions.map((question, currentQuestionIndex) =>
        currentQuestionIndex === questionIndex
          ? normalizeQuestion({
              ...question,
              options: question.options.filter((_option, currentOptionIndex) => currentOptionIndex !== optionIndex),
            })
          : question,
      ),
    })),
    addDefaultQuiz: () => {
      setDraftOverride(createDefaultSafetyQuiz());
      setHasDraftOverride(true);
      setValidationError(null);
      setSavedMessage(null);
    },
    reset: () => {
      setDraftOverride(null);
      setHasDraftOverride(false);
      setValidationError(null);
      setSavedMessage(null);
    },
    save: async () => {
      if (!draft) {
        setValidationError('Add a quiz before saving.');
        setSavedMessage(null);
        return;
      }

      const error = validateSafetyQuizPayload(draft);
      if (error) {
        setValidationError(error);
        setSavedMessage(null);
        return;
      }

      await saveMutation.mutateAsync(draft);
    },
    deleteQuiz: async () => {
      await deleteMutation.mutateAsync();
    },
  };
}

function normalizeQuestion(question: QuizQuestion): QuizQuestion {
  const correctIndex = question.options.length === 0
    ? 0
    : Math.min(question.correctIndex, question.options.length - 1);

  return { ...question, correctIndex };
}

function createDefaultQuestion(sequence: number): QuizQuestion {
  return {
    id: `question-${Date.now()}-${sequence}`,
    question: '',
    options: ['Correct answer', 'Incorrect answer'],
    correctIndex: 0,
    explanation: '',
  };
}

function createDefaultSafetyQuiz(): SafetyQuiz {
  return {
    id: `qbs-${Date.now()}`,
    title: 'QBS Safety Quiz',
    focus: 'de-escalation',
    weeklyFocus: {
      title: 'Weekly Safety Focus',
      description: 'Add the weekly safety focus for staff.',
    },
    keyReminders: ['Add a key reminder.'],
    questions: [
      {
        id: 'question-1',
        question: 'Add the first QBS safety question.',
        options: ['Correct answer', 'Incorrect answer'],
        correctIndex: 0,
        explanation: 'Explain why the correct answer is safest.',
      },
    ],
  };
}
