import ModalCalendar from "@/components/ModalCalendar";
import ModalTags, { ITags } from "@/components/ModalTags";
import Task from "@/components/task";
import Dialog from "@/components/ui/Dialog";
import ModalWindow from "@/components/ui/Modal";
import { withTitle } from "@/constructors/Component";
import { UrlsTitle } from "@/enums/urls";
import apiClient from "@/services/api";
import { cn } from "@/utils/class-merge";
import {
  BookOpenIcon,
  CalendarDaysIcon,
  DocumentDuplicateIcon,
  InboxArrowDownIcon,
  PencilIcon,
  TrashIcon,
} from "@heroicons/react/24/outline";
import { FunctionComponent } from "preact";
import { useEffect, useMemo, useState } from "preact/hooks";
import { Calendar, CalendarDateTemplateEvent } from "primereact/calendar";
import { Nullable } from "primereact/ts-helpers";
import { SubmitHandler, useForm } from "react-hook-form";
import {
  IApiResponse,
  IAPITag,
  ICreateTaskResponse,
  IDeleteTaskResponse,
  IEditTaskResponse,
  ITask,
  ITaskDetails,
  ITaskForm,
  IViewTagsResponse,
} from "./profile_tasks.dto";

const calendarStyles = {
  root: "inline-flex w-full relative",
  input: "font-sans text-base text-gray-600 bg-white p-3",
  panel: "bg-white min-w-full p-2",
  header: "flex items-center justify-between p-2 text-gray-700 font-semibold m-0 mb-4",
  title: "leading-8 mx-auto text-xl",
  previousButton: "flex items-center justify-center cursor-pointer w-8 h-8 text-gray-600",
  nextButton: "flex items-center justify-center cursor-pointer w-8 h-8 text-gray-600",
  table: "border-collapse w-full",
  tableHeaderCell: "p-2 text-center",
  weekDay: "text-gray-600 font-normal pb-4",
  monthTitle: "text-gray-700 font-semibold mr-2",
  yearTitle: "text-gray-700 font-semibold",
  monthPicker: "grid grid-cols-3 gap-2",
  yearPicker: "grid grid-cols-2 gap-2",
  month:
    "p-2 text-center cursor-pointer rounded-lg hover:bg-[rgba(251,194,199,0.1)] [&.p-highlight]:bg-[rgba(251,194,199,0.2)]",
  year: "p-2 text-center cursor-pointer rounded-lg hover:bg-[rgba(251,194,199,0.1)] [&.p-highlight]:bg-[rgba(251,194,199,0.2)]",
};

const ProfileCalendar: FunctionComponent = () => {
  const [currentDate, setCurrentDate] = useState(new Date());
  const [tasks, setTasks] = useState<ITask[]>([]);
  const [selectedTasks, setSelectedTasks] = useState<ITask[]>([]);
  const [openModal, setIsOpen] = useState(false);
  const [openModalCalendar, setOpenModalCalendar] = useState(false);
  const [openModalTags, setOpenModalTags] = useState(false);
  const [isEdit, setIsEdit] = useState(false);
  const [isEditModal, setIsEditModal] = useState(false);
  const [editContent, setEditContent] = useState<ITask | null>(null);
  const [calendarDate, setCalendarDate] = useState<Nullable<Date>>();
  const [tags, setTags] = useState<ITags>({ first: 0, second: 0, overdue: false });
  const [showDeleteDialog, setShowDeleteDialog] = useState(false);
  const [subjectChoices, setSubjectChoices] = useState<IAPITag[]>([]);
  const [taskTypeChoices, setTaskTypeChoices] = useState<IAPITag[]>([]);
  const [isLoading, setIsLoading] = useState(true);

  const {
    handleSubmit,
    register,
    reset,
    setError,
    formState: { errors },
  } = useForm<ITaskForm>({
    defaultValues: {
      subject: {
        name: "",
        id: 0,
      },
      taskType: {
        name: "",
        id: 0,
      },
    },
  });

  useEffect(() => {
    fetchTasks();
    fetchTags();
  }, []);

  const fetchTags = async () => {
    try {
      const response = await apiClient<IViewTagsResponse>("/api/tags/view_tags/");
      setSubjectChoices(response.subjects);
      setTaskTypeChoices(response.taskTypes);
    } catch (error) {
      console.error("Failed to fetch tags:", error);
    }
  };

  const fetchTasks = async () => {
    try {
      setIsLoading(true);
      const response = await apiClient<IApiResponse>("/api/tasks/view_tasks/");

      const convertedTasks: ITask[] = response.tasks.map((apiTask) => ({
        id: apiTask.id.toString(),
        name: apiTask.title,
        checked: apiTask.isCompleted,
        date: new Date(apiTask.due_date),
        description: apiTask.description,
        priority: apiTask.priority,
        subject: apiTask.subject,
        taskType: apiTask.taskType,
        new: false,
      }));

      setTasks(convertedTasks);
    } catch (error) {
      console.error("Failed to fetch tasks:", error);
    } finally {
      setIsLoading(false);
    }
  };

  const example_tags = useMemo(
    () => ({
      first: subjectChoices,
      second: taskTypeChoices,
    }),
    [subjectChoices, taskTypeChoices]
  );

  const saveTask: SubmitHandler<ITaskForm> = async (data) => {
    if (!calendarDate) {
      setError("date", { message: "Выберите дату" });
      return;
    }
    if ((!editContent?.subject.id || !editContent.taskType.id) && (!tags.first || !tags.second)) {
      setError("subject", { message: "Выберите теги" });
      return;
    }

    try {
      const selectedSubject = editContent?.subject.id || tags.first;
      const selectedTaskType = editContent?.taskType.id || tags.second;

      // Format date to DD-MM-YYYYTHH:MM
      const formattedDate = calendarDate
        .toLocaleString("en-GB", {
          day: "2-digit",
          month: "2-digit",
          year: "numeric",
          hour: "2-digit",
          minute: "2-digit",
          hour12: false,
        })
        .replace(",", "T")
        .replace(/\//g, "-")
        .replace("T ", "T");

      const taskData = {
        title: data.name,
        description: data.description || "",
        subject: selectedSubject,
        taskType: selectedTaskType,
        dateTime_due: formattedDate,
        telegram_notifications: false,
      };

      if (!editContent) {
        const response = await apiClient<ICreateTaskResponse>("/api/tasks/create_task/", {
          method: "POST",
          body: JSON.stringify(taskData),
        });

        if (!response.success) {
          throw new Error(response.message);
        }
      } else {
        const response = await apiClient<IEditTaskResponse>(`/api/tasks/edit_task/${editContent.id}/`, {
          method: "PUT",
          body: JSON.stringify(taskData),
        });

        if (!response.success) {
          throw new Error(response.message);
        }
      }

      await fetchTasks();
      setIsOpen(false);
      setTags({ first: 0, second: 0, overdue: false });
    } catch (error) {
      console.error("Failed to save task:", error);
    }
  };

  const handleDeleteTask = async () => {
    if (!editContent) return;

    try {
      const response = await apiClient<IDeleteTaskResponse>(`/api/tasks/delete_task/${editContent.id}/`, {
        method: "DELETE",
      });

      if (!response.success) {
        throw new Error(response.message);
      }

      await fetchTasks();
      setIsOpen(false);
      setShowDeleteDialog(false);
    } catch (error) {
      console.error("Failed to delete task:", error);
    }
  };

  const handleTaskCheck = async (taskId: string) => {
    try {
      await apiClient(`/api/tasks/toggle_complete_task/${taskId}/`, {
        method: "PATCH",
      });

      setTasks((prevTasks) =>
        prevTasks.map((task) => (task.id === taskId ? { ...task, checked: !task.checked } : task))
      );
    } catch (error) {
      console.error("Failed to mark task:", error);
    }
  };

  const handleViewTask = async (taskId: string) => {
    try {
      const taskDetails = await apiClient<ITaskDetails>(`/api/tasks/view_task/${taskId}/`);

      const task: ITask = {
        id: taskId,
        name: taskDetails.title,
        checked: false,
        date: new Date(taskDetails.dateTime_due),
        description: taskDetails.description,
        subject: taskDetails.subject,
        taskType: taskDetails.task_type,
        priority: taskDetails.priority,
      };

      setIsOpen(true);
      setIsEdit(true);
      setEditContent(task);
      setCalendarDate(task.date);
      setIsEditModal(false);
    } catch (error) {
      console.error("Failed to fetch task details:", error);
    }
  };

  useEffect(() => {
    if (!currentDate) return;

    const tasksForDate = tasks.filter((task) => {
      const taskDate = task.date;
      return (
        taskDate.getDate() === currentDate.getDate() &&
        taskDate.getMonth() === currentDate.getMonth() &&
        taskDate.getFullYear() === currentDate.getFullYear()
      );
    });

    setSelectedTasks(tasksForDate);
  }, [currentDate, tasks]);

  useEffect(() => {
    if (editContent) reset({ ...editContent, date: editContent.date.toISOString().slice(0, 16) });
    else reset();
  }, [editContent]);

  useEffect(() => {
    if (!editContent) return;
    const newEditContent = editContent;
    if (tags.first) newEditContent.subject = subjectChoices.find((tag) => tag.id === tags.first)!;
    if (tags.second) newEditContent.taskType = taskTypeChoices.find((tag) => tag.id === tags.second)!;
    setEditContent(newEditContent);
  }, [tags]);

  const tasksCount = (date: CalendarDateTemplateEvent) => {
    return tasks.filter((task) => {
      const taskDate = task.date;
      return (
        taskDate.getDate() === date.day && taskDate.getMonth() === date.month && taskDate.getFullYear() === date.year
      );
    }).length;
  };

  const hasTasksOnDate = (date: CalendarDateTemplateEvent) => {
    return tasks.some((task) => {
      const taskDate = task.date;
      return (
        taskDate.getDate() === date.day && taskDate.getMonth() === date.month && taskDate.getFullYear() === date.year
      );
    });
  };

  const dateTemplate = (date: CalendarDateTemplateEvent) => {
    const isHighlighted = hasTasksOnDate(date);
    const countT = tasksCount(date);
    const isSelected =
      currentDate &&
      currentDate.getDate() === date.day &&
      currentDate.getMonth() === date.month &&
      currentDate.getFullYear() === date.year;
    const isToday =
      new Date().getDate() === date.day &&
      new Date().getMonth() === date.month &&
      new Date().getFullYear() === date.year;
    return (
      <div
        className={cn(
          "relative flex h-20 w-full cursor-pointer items-start justify-start rounded-lg p-2",
          "hover:bg-[rgba(251,194,199,0.1)]",
          {
            "bg-[rgba(251,194,199,0.4)]": isSelected,
            "bg-[rgba(251,194,199,0.2)]": isToday && !isSelected,
          }
        )}
      >
        <span>{date.day}</span>
        {isHighlighted && (
          <div class="absolute top-2 right-2 flex h-fit w-2 flex-col items-center gap-1 md:h-2 md:w-fit md:flex-row">
            {Array.from({ length: countT > 3 ? 3 : countT }).map((_, i) => (
              <span key={i} className="size-2 rounded-full bg-pink-400" />
            ))}
            {countT > 3 && <span className="text-xs font-bold text-pink-400 select-none">+</span>}
          </div>
        )}
      </div>
    );
  };

  const formatDate = (date: Date) => {
    return new Intl.DateTimeFormat("ru-RU", {
      day: "numeric",
      month: "long",
      year: "numeric",
    }).format(date);
  };

  const pt = {
    root: { className: calendarStyles.root },
    input: { root: { className: calendarStyles.input } },
    panel: { className: calendarStyles.panel },
    header: { className: calendarStyles.header },
    title: { className: calendarStyles.title },
    previousButton: { className: calendarStyles.previousButton },
    nextButton: { className: calendarStyles.nextButton },
    table: { className: calendarStyles.table },
    tableHeaderCell: { className: calendarStyles.tableHeaderCell },
    weekDay: { className: calendarStyles.weekDay },
    monthTitle: { className: calendarStyles.monthTitle },
    yearTitle: { className: calendarStyles.yearTitle },
    monthPicker: { className: calendarStyles.monthPicker },
    yearPicker: { className: calendarStyles.yearPicker },
    month: { className: calendarStyles.month },
    year: { className: calendarStyles.year },
  };

  return (
    <div class="flex w-full flex-col items-center">
      {isLoading ? (
        <div class="flex w-full flex-1 items-center justify-center">
          <div class="text-2xl">Загрузка...</div>
        </div>
      ) : (
        <>
          <ModalTags
            refreshTags={fetchTags}
            isOpen={openModalTags}
            setIsOpen={setOpenModalTags}
            tagsList={example_tags}
            value={tags}
            onClose={() => {
              setTags({ first: 0, second: 0, overdue: false });
            }}
            onChange={setTags}
          />
          <ModalCalendar
            isOpen={openModalCalendar}
            setIsOpen={setOpenModalCalendar}
            onClose={() => {
              if (isEdit && !isEditModal) setCalendarDate(null);
            }}
            onChange={(e) => isEditModal && setCalendarDate(e.value)}
            value={calendarDate!}
          />
          <ModalWindow
            isOpen={openModal}
            setIsOpen={setIsOpen}
            onClose={() => {
              setIsEdit(false);
              setEditContent(null);
              setIsEditModal(false);
              setTags({ first: 0, second: 0, overdue: false });
              setCalendarDate(null);
            }}
          >
            {isEdit && editContent && (
              <form
                class="flex h-full w-full flex-col items-start justify-between"
                onSubmit={(e) => {
                  e.preventDefault();
                  if (isEditModal) handleSubmit(saveTask)();
                  else setIsEditModal(!isEditModal);
                }}
              >
                <div class="flex w-full flex-row items-start justify-between">
                  <div class="flex flex-1 flex-col gap-1 pe-2">
                    <input
                      class={cn("w-full p-2 text-2xl outline-0", {
                        "rounded-md bg-gray-400/30 ring-1 ring-gray-400": isEditModal,
                      })}
                      disabled={!isEditModal}
                      placeholder="Название"
                      {...register("name", {
                        required: "Заполните название",
                        maxLength: { value: 20, message: "Максимум 20 символов в названии" },
                      })}
                    />
                    <textarea
                      class={cn("h-[5rem] w-full resize-none p-2 outline-0", {
                        "rounded-md bg-gray-400/30 ring-1 ring-gray-400": isEditModal,
                      })}
                      disabled={!isEditModal}
                      placeholder={isEditModal ? "Описание" : ""}
                      {...register("description", {
                        maxLength: { value: 200, message: "Максимум 200 символов в описании" },
                      })}
                    />
                    <input
                      type="datetime-local"
                      value={calendarDate ? calendarDate.toISOString().slice(0, 16) : ""}
                      hidden
                      {...register("date")}
                    />
                    <input type="checkbox" hidden {...register("checked")} />
                  </div>
                  <div class="flex flex-row gap-4">
                    <div
                      className="flex cursor-pointer flex-col items-center gap-3"
                      onClick={() => {
                        if (isEditModal) {
                          handleSubmit(saveTask)();
                          setIsEditModal(!isEditModal);
                        } else setIsEditModal(!isEditModal);
                      }}
                    >
                      {isEditModal ? (
                        <>
                          <InboxArrowDownIcon class="size-6" />
                          <p class="text-[0.7rem]">Сохранить</p>
                        </>
                      ) : (
                        <>
                          <PencilIcon class="size-6" />
                          <p class="text-[0.7rem]">Редактировать</p>
                        </>
                      )}
                    </div>
                    <div
                      className="flex cursor-pointer flex-col items-center gap-3"
                      onClick={() => setShowDeleteDialog(true)}
                    >
                      <TrashIcon class="size-6" />
                      <p class="text-[0.7rem]">Удалить</p>
                    </div>
                  </div>
                </div>
                {errors.name && <p class="text-red-500">{errors.name.message}</p>}
                {errors.description && <p class="text-red-500">{errors.description.message}</p>}
                {errors.date && <p class="text-red-500">{errors.date.message}</p>}
                {errors.subject && <p class="text-red-500">{errors.subject.message}</p>}
                <div class="flex flex-col items-center gap-6 self-center md:flex-row md:justify-start md:self-start">
                  <div
                    class={cn(
                      "flex h-full flex-row items-center gap-1 rounded-2xl bg-[rgba(251,194,199,0.38)] px-2 py-1",
                      {
                        "cursor-pointer": isEditModal,
                      }
                    )}
                    onClick={() => {
                      if (!isEditModal) return;
                      setOpenModalCalendar(true);
                      setCalendarDate(editContent.date);
                    }}
                  >
                    <CalendarDaysIcon class="size-10" />
                    <p>
                      {Intl.DateTimeFormat("ru-RU", {
                        day: "2-digit",
                        month: "2-digit",
                        year: "numeric",
                        hour: "2-digit",
                        minute: "2-digit",
                      }).format(calendarDate!)}
                    </p>
                  </div>
                  <div
                    class={cn(
                      "flex h-full flex-col items-start gap-1 rounded-2xl bg-[rgba(251,194,199,0.38)] px-4 py-2",
                      {
                        "cursor-pointer": isEditModal,
                      }
                    )}
                    onClick={() => {
                      if (!isEditModal) return;
                      setTags({ first: editContent.subject.id, second: editContent.taskType.id, overdue: false });
                      setOpenModalTags(true);
                    }}
                  >
                    <p class="flex flex-row gap-2">
                      <BookOpenIcon class="size-5" />
                      {editContent.subject.name}
                    </p>
                    <p class="flex flex-row gap-2">
                      <DocumentDuplicateIcon class="size-5" />
                      {editContent.taskType.name}
                    </p>
                  </div>
                </div>
              </form>
            )}
          </ModalWindow>
          <Dialog
            isOpen={showDeleteDialog}
            setIsOpen={setShowDeleteDialog}
            title="Удаление задачи"
            onConfirm={handleDeleteTask}
            confirmText="Удалить"
            cancelText="Отмена"
          >
            <p class="mb-6 text-sm sm:text-[1rem]">"Вы уверены, что хотите удалить эту задачу?"</p>
          </Dialog>
          <Calendar
            value={currentDate}
            onChange={(e) => setCurrentDate(e ? e.value! : new Date())}
            inline
            pt={pt}
            dateTemplate={dateTemplate}
            className="[&_.p-datepicker]:!border-0 [&_.p-datepicker-calendar]:border-separate [&_.p-datepicker-calendar]:border-spacing-2 [&_td]:rounded-lg [&_td]:border [&_td]:border-[rgba(251,194,199,0.38)]"
          />

          <div class="mt-8 w-full px-4">
            <h2 class="mb-4 text-2xl font-semibold">Задачи на {formatDate(currentDate)}</h2>
            {selectedTasks.length > 0 ? (
              <div class="flex flex-col gap-4">
                {selectedTasks.map((task) => (
                  <Task
                    key={task.id}
                    name={task.name}
                    checked={task.checked}
                    priority={task.priority}
                    overdue={task.date < new Date()}
                    onClick={() => handleViewTask(task.id)}
                    onMarkClick={() => handleTaskCheck(task.id)}
                  />
                ))}
              </div>
            ) : (
              <div class="rounded-lg bg-[rgba(251,194,199,0.2)] p-4 text-center">На этот день задач нет</div>
            )}
          </div>
        </>
      )}
    </div>
  );
};

export default withTitle(UrlsTitle.CALENDAR, ProfileCalendar);
