import { IconPhoto, IconPlayerSkipForward } from '@material-hu/icons/tabler';
import { type Theme } from '@material-hu/mui/styles';

import { TaskTypes } from '@material-hu/components/composed-components/learning';

import { type FilesExtensions, FileTypes } from 'src/types/attachments';
import { getFileExtension } from 'src/utils/attachments';

import { FILE_EXTENSION_ICONS } from './constants';
import { type TParams as GetCoursesParams } from './hooks/useGetCourses';
import { type EvaluationFormValues } from './Tasks/components/TaskEvaluation';
import {
  ChoiceResult,
  type Course,
  CourseStatus,
  type EvaluationTask,
  type Module,
  type Question,
  QuestionType,
  type SurveyFormData,
  type SurveyFormResponse,
  type SurveyQuestion,
  type Task,
  TaskStatus,
} from './types';

export const getTaskCount = (course: Course, finished = false): number => {
  if (!course?.modules) return 0;

  return course.modules
    .flatMap(module => module.tasks)
    .filter(task => !finished || isTaskFinished(task)).length;
};

/**
 * Formats survey response data for submission to the API.
 *
 * This function transforms the raw form data into the expected format for the API,
 * handling different question types appropriately:
 * - For text questions, ensures the answer is a string
 * - For multiple choice questions, converts the numeric selection to the corresponding choice text
 * - For rating questions, adjusts the index (subtracts 1 from the user-facing value)
 *
 * @param questions - Array of survey questions with their types and options
 * @param formData - Raw form response data keyed by question ID
 * @returns Formatted survey data ready for submission
 */
export const formatSurveyData = (
  questions: SurveyQuestion[] | undefined,
  formData: SurveyFormResponse,
): SurveyFormData => {
  if (!questions) return { questionAnswers: [] };

  const questionAnswers = questions.map(question => {
    const answerValue = formData[question.id];

    let formattedAnswer = null;

    if (question.type === QuestionType.MULTIPLE_CHOICE) {
      formattedAnswer = [answerValue as string];
    } else {
      formattedAnswer = answerValue as string;
    }

    return {
      id: question.id,
      answer: formattedAnswer,
      comment: undefined,
    };
  });

  return { questionAnswers };
};

export const isTaskFinished = (task: Task | undefined) => {
  if (!task) return false;

  return (
    task.status === TaskStatus.FINISHED_OK ||
    task.status === TaskStatus.FINISHED_FAIL
  );
};

export const isTaskInProgress = (task: Task | undefined) => {
  if (!task) return false;

  return task.status === TaskStatus.IN_PROGRESS;
};

export const isTaskGraded = (task: Task) =>
  isTaskFinished(task) && 'grade' in task && typeof task?.grade === 'number';

export const shouldGetSurvey = (course: Course | undefined) => {
  if (!course) return false;

  return (
    !!course &&
    course.hasSurvey &&
    course.status === CourseStatus.FINISHED &&
    !course.hasCompletedSurvey
  );
};

export const hasToShowSurvey = (
  course: Course | undefined,
  survey: SurveyQuestion[] | undefined,
  surveyShown: boolean,
) => {
  if (!course || !survey) return false;

  return (
    !!course &&
    !!survey &&
    !surveyShown &&
    course.hasSurvey &&
    !course.hasCompletedSurvey &&
    course.status === CourseStatus.FINISHED
  );
};

/**
 * Determines if a task can be started based on the completion status of previous tasks.
 * A task can be started if:
 * 1. It's the first task in the first module, OR
 * 2. If the course is not sequential, all tasks are available
 * 3. All previous tasks in the current module and all tasks in previous modules are finished
 *
 * @param modules - Array of course modules
 * @param currentModuleIndex - Index of the current module
 * @param currentTaskIndex - Index of the task to check
 * @param isSequential - Whether the course is sequential
 * @returns boolean indicating if the task can be started
 */
export const canStartTask = (
  modules: Module[],
  moduleIndex: number,
  taskIndex: number,
  isSequential: boolean,
) => {
  // First task in the first module is always available
  if (isFirstTask(moduleIndex, taskIndex)) return true;

  // If the course is not sequential, all tasks are available
  if (!isSequential) return true;

  // Check all previous modules and tasks
  for (let modulePointer = 0; modulePointer <= moduleIndex; modulePointer++) {
    const module = modules[modulePointer];
    const isCurrentModule = modulePointer === moduleIndex;

    // For current module, check tasks up to current task
    // For previous modules, check all tasks
    const tasksToCheck = isCurrentModule
      ? module.tasks.slice(0, taskIndex)
      : module.tasks;

    // If any task is not finished, the current task cannot be started
    const hasUnfinishedTask = tasksToCheck.some(task => !isTaskFinished(task));
    if (hasUnfinishedTask) return false;
  }

  return true;
};

export const isFirstTask = (
  currentModuleIndex: number,
  currentTaskIndex: number,
) => {
  return currentModuleIndex === 0 && currentTaskIndex === 0;
};

export const getFileExtensionIcon = (type: string, fileName: string) => {
  if (type === FileTypes.IMAGE) return IconPhoto;
  if (type === FileTypes.VIDEO) return IconPlayerSkipForward;

  const fileExtension = getFileExtension(fileName);

  return FILE_EXTENSION_ICONS[fileExtension as FilesExtensions];
};

export const exceedsAttempts = (task: EvaluationTask | undefined) => {
  if (!task) return false;
  if (!task.attempts || !task.maximumAttempts) return false;

  return task.attempts > task.maximumAttempts;
};

export const isEvaluationTaskFinishPending = (
  task: EvaluationTask | undefined,
) => isPendingTask(task) && exceedsAttempts(task);

export const isPendingTask = (task: Task | undefined) => {
  if (!task) return false;

  const status = task.status;

  return (
    status === TaskStatus.PENDING ||
    status === TaskStatus.IN_PROGRESS ||
    status === TaskStatus.FAILED
  );
};

export const getFirstPendingTask = (modules: Module[]) => {
  for (let moduleIndex = 0; moduleIndex < modules.length; moduleIndex++) {
    const tasks = modules[moduleIndex].tasks;

    for (let taskIndex = 0; taskIndex < tasks.length; taskIndex++) {
      const task = tasks[taskIndex];

      if (isPendingTask(task)) {
        return {
          moduleIndex,
          taskIndex,
          task,
        };
      }
    }
  }

  return {
    moduleIndex: -1,
    taskIndex: -1,
    task: null as Task | null,
  };
};

export const isEvaluationTaskFinished = (task: EvaluationTask | undefined) =>
  isTaskFinished(task) || exceedsAttempts(task);

export const extractMinutes = (timeString: string) => {
  const minutesPart = timeString.split(':')[0];
  return parseInt(minutesPart, 10);
};

export const transformEvaluationFormData = (
  formValues: EvaluationFormValues,
  questions: Question[],
) => {
  const questionAnswers = questions.map(question => ({
    id: question.id,
    answer: question.type === QuestionType.TEXT ? '' : ([] as string[]),
  }));

  questions.forEach((question, questionIndex) => {
    const dataSet = formValues[questionIndex];
    const resultIndex = questionAnswers.findIndex(
      item => item.id === question.id,
    );

    switch (question.type) {
      case QuestionType.TEXT:
        questionAnswers[resultIndex].answer = dataSet as string;
        break;
      case QuestionType.MULTIPLE_CHOICE: {
        const answerIndex = (dataSet as boolean[]).findIndex(choice => choice);
        if (answerIndex === -1) return;

        questionAnswers[resultIndex].answer = [
          question.choices?.[answerIndex] as string,
        ];
        break;
      }
      case QuestionType.CHECKBOX: {
        const answer: string[] = [];
        (dataSet as boolean[]).forEach((choice, index) => {
          if (choice) {
            answer.push(question.choices?.[index] as string);
          }
        });

        questionAnswers[resultIndex].answer = answer;
        break;
      }
    }
  });

  return { questionAnswers };
};

export const validateEvaluationFormData = (
  formValues: EvaluationFormValues,
  questions: Question[],
) => {
  if (!questions || !questions.length) return false;

  return questions.every((question, questionIndex) => {
    let isValid = false;
    const dataSet = formValues[questionIndex] || [];

    if (question.type === QuestionType.TEXT) {
      isValid = dataSet.length > 0;
    } else {
      isValid = (dataSet as boolean[]).some(v => v);
    }

    return isValid;
  });
};

export function getChoiceResult(
  choice: string,
  answers: string[],
  correctAnswers: string[],
) {
  const isAnswered = answers?.includes(choice) ?? false;
  const isCorrect = correctAnswers?.includes(choice) ?? false;

  if (isAnswered && isCorrect) {
    return ChoiceResult.CORRECT;
  } else if (isAnswered) {
    return ChoiceResult.INCORRECT;
  } else if (isCorrect) {
    return ChoiceResult.MISSING;
  } else {
    return ChoiceResult.NOT_SELECTED;
  }
}

export const getTaskPosition = (course: Course | undefined, taskId: number) => {
  let position = { moduleIndex: -1, taskIndex: -1 };

  if (!course || !taskId) return position;

  course.modules.forEach((module, moduleIndex) => {
    module.tasks.forEach((task, taskIndex) => {
      if (task.id === taskId) {
        position = { moduleIndex, taskIndex };
      }
    });
  });

  return position;
};

export const isCourseFirstTask = (
  course: Course | undefined,
  taskId: number | undefined,
) => {
  if (!course || !taskId) return false;

  const { moduleIndex, taskIndex } = getTaskPosition(course, taskId);

  if (moduleIndex === -1 || taskIndex === -1) return false;

  return isFirstTask(moduleIndex, taskIndex);
};

export const isMultimediaTask = (task: Task | undefined) => {
  if (!task) return false;

  return (
    task.type === TaskTypes.VIDEO ||
    (task.type === TaskTypes.READING && !!task.url)
  );
};

export const getPreviousTask = (course: Course, taskId: number) => {
  if (!course || !taskId) return null;

  const { moduleIndex, taskIndex } = getTaskPosition(course, taskId);
  if (moduleIndex === -1 || taskIndex === -1) return null;

  if (taskIndex - 1 >= 0) {
    return course.modules[moduleIndex].tasks[taskIndex - 1];
  }

  if (moduleIndex - 1 >= 0) {
    const previousModule = course.modules[moduleIndex - 1];
    return previousModule.tasks[previousModule.tasks.length - 1];
  }

  return null;
};

export const getNextTask = (course: Course, taskId: number) => {
  if (!course || !taskId) return null;

  const { moduleIndex, taskIndex } = getTaskPosition(course, taskId);
  if (moduleIndex === -1 || taskIndex === -1) return null;

  if (taskIndex + 1 < course.modules[moduleIndex].tasks.length) {
    return course.modules[moduleIndex].tasks[taskIndex + 1];
  }

  if (moduleIndex + 1 < course.modules.length) {
    return course.modules[moduleIndex + 1].tasks[0];
  }

  return null;
};

export const isPendingSignature = (course: Course) =>
  course?.status === CourseStatus.PENDING_SIGNATURE;

export const isCourseCompletion = (course: Course, updatedCourse: Course) =>
  updatedCourse.passed && !course.passed;

export const isModuleFinished = (module: Module) => {
  if (!module) return false;
  return module.tasks.every(task => isTaskFinished(task));
};

export const isModuleInProgress = (module: Module) => {
  if (!module) return false;
  return module.tasks.some(task => isTaskInProgress(task));
};

export const getTaskByPosition = (
  course: Course | undefined,
  { taskIndex, moduleIndex }: ReturnType<typeof getTaskPosition>,
) => {
  if (!course || moduleIndex === -1 || taskIndex === -1) return null;

  return course.modules[moduleIndex]?.tasks[taskIndex];
};

export const getTaskById = (course: Course | undefined, taskId: number) => {
  const taskPosition = getTaskPosition(course, taskId);
  return getTaskByPosition(course, taskPosition);
};

export const getModuleByTaskId = (
  course: Course,
  taskId: number | undefined,
) => {
  if (!course?.modules || !taskId) return null;

  const { moduleIndex } = getTaskPosition(course, taskId);

  return course.modules[moduleIndex] || null;
};

export const showCertificate = (course: Course) => {
  return course?.passed && course?.issueCertificate;
};

export const getCourseFiltersCount = (params: GetCoursesParams) => {
  let count = 0;

  if (params?.type) count++;
  if (params?.sort) count++;

  return count;
};

export const getCurrentModule = (course: Course) => {
  const currentModule = course.modules.find(isModuleInProgress);
  if (!currentModule) return course.modules[0];
  return currentModule;
};

export const getModuleFinishedTaskCount = (module: Module) => {
  return module.tasks.filter(task => isTaskFinished(task)).length ?? 0;
};

export const getDonutChartColors = (palette: Theme['palette']) => ({
  fill: palette.new.graphics.brand[600],
  track: palette.new.background.layout.brand,
});

export const getEvaluationDonutChartTrackColor = (palette: Theme['palette']) =>
  palette.new.background.elements.grey;
