import { type FC, useEffect, useMemo, useState } from "react";
import { useTranslation } from "react-i18next";
import { toast } from '../../../../components/Toast';
import { useGetUsersInfinite } from "../../../users/hooks/useUserData";
import TaskDetailAttachmentPopover from "./attachment/TaskDetailAttachmentPopover";
import TaskDetailDatePopover from "./date/TaskDetailDatePopover";
import { parseApiDate, toApiDate } from "./date/utils";
import type DateObject from "react-date-object";
import TaskDetailChecklistPopover from "./checklist/TaskDetailChecklistPopover";
import TaskDetailLabelsPopover from "./labels/TaskDetailLabelsPopover";
import type { LabelsView, TaskLabel } from "./labels/types";
import TaskDetailActionBar from "./TaskDetailActionBar";
import TaskDetailMetadataPreview from "./TaskDetailMetadataPreview";
import type { TaskDetailTab } from "./types";
import TaskDetailUsersPopover from "./users/TaskDetailUsersPopover";
import TaskDetailTimePopover from "./time/TaskDetailTimePopover";
import type { TaskUser } from "./users/types";
import type { UserItemType } from "../../../users/types/UserTypes";
import type { TaskDetailType } from "../../task/types/TaskTypes";
import { useCreateCheckListItem, useCreateTaskAttachment, useCreateTaskRemark, useUpdateTask } from "../../task/hooks/useTaskData";
import { useSingleUpload } from "../../../service/hooks/useServiceData";
import { ErrorType } from "../../../../helpers/types";

type Props = {
  activeTab: TaskDetailTab | null;
  onTabChange: (tab: TaskDetailTab) => void;
  taskDetail?: TaskDetailType;
  taskId: string;
};

const TaskDetailToolbar: FC<Props> = ({ activeTab, onTabChange, taskDetail, taskId }) => {
  const { t } = useTranslation("global");
  const createTaskRemark = useCreateTaskRemark();
  const createCheckListItem = useCreateCheckListItem();
  const createTaskAttachment = useCreateTaskAttachment();
  const singleUpload = useSingleUpload();
  const updateTask = useUpdateTask();
  const isUsersOpen = activeTab === "users";
  const [userSearch, setUserSearch] = useState("");
  const [debouncedUserSearch, setDebouncedUserSearch] = useState("");
  const {
    data: usersData,
    isPending: isUsersPending,
    isFetchingNextPage: isFetchingNextUsersPage,
    fetchNextPage: fetchNextUsersPage,
    hasNextPage: hasNextUsersPage,
  } = useGetUsersInfinite(debouncedUserSearch, undefined, isUsersOpen);
  const [labelsView, setLabelsView] = useState<LabelsView>("list");
  const [labels, setLabels] = useState<TaskLabel[]>([]);
  const [selectedLabelIds, setSelectedLabelIds] = useState<Set<string>>(new Set());
  const [selectedUserIds, setSelectedUserIds] = useState<Set<string>>(new Set());
  const [startDate, setStartDate] = useState<DateObject | null>(null);
  const [endDate, setEndDate] = useState<DateObject | null>(null);

  useEffect(() => {
    const timeoutId = window.setTimeout(() => {
      setDebouncedUserSearch(userSearch.trim());
    }, 300);

    return () => window.clearTimeout(timeoutId);
  }, [userSearch]);

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

    const taskLabels = taskDetail.labels ?? taskDetail.remarks ?? [];

    if (taskLabels.length) {
      setLabels(taskLabels);
      setSelectedLabelIds(new Set(taskLabels.map((label) => label.id)));
    } else {
      setLabels([]);
      setSelectedLabelIds(new Set());
    }

    if (taskDetail.users?.length) {
      setSelectedUserIds(new Set(taskDetail.users.map((user) => user.id)));
    } else {
      setSelectedUserIds(new Set());
    }

    setStartDate(parseApiDate(taskDetail.startDate));
    setEndDate(parseApiDate(taskDetail.endDate));
  }, [taskDetail]);

  const selectedLabels = labels.filter((label) => selectedLabelIds.has(label.id));
  const users = useMemo((): TaskUser[] => {
    const apiUsers: TaskUser[] =
      usersData?.pages.flatMap(
        (page) =>
          page.data?.users?.map((user: UserItemType) => ({
            id: user.id,
            name: `${user.firstName} ${user.lastName}`.trim(),
            avatar: user.profilePic,
          })) ?? [],
      ) ?? [];
    const taskUsers: TaskUser[] =
      taskDetail?.users?.map((user) => ({
        id: user.id,
        name: `${user.firstName} ${user.lastName}`.trim(),
        avatar: user.profilePic,
      })) ?? [];
    const userMap = new Map<string, TaskUser>(apiUsers.map((user) => [user.id, user]));

    taskUsers.forEach((user) => {
      const existing = userMap.get(user.id);

      if (existing) {
        if (!existing.avatar && user.avatar) {
          userMap.set(user.id, { ...existing, avatar: user.avatar });
        }
        return;
      }

      userMap.set(user.id, user);
    });

    return Array.from(userMap.values());
  }, [usersData?.pages, taskDetail?.users]);
  const listUsers = useMemo((): TaskUser[] => {
    return (
      usersData?.pages.flatMap(
        (page) =>
          page.data?.users?.map((user: UserItemType) => ({
            id: user.id,
            name: `${user.firstName} ${user.lastName}`.trim(),
            avatar: user.profilePic,
          })) ?? [],
      ) ?? []
    );
  }, [usersData?.pages]);
  const selectedUsers = users.filter((user) => selectedUserIds.has(user.id));
  const isLabelsOpen = activeTab === "labels";
  const isChecklistOpen = activeTab === "checklist";
  const isAttachmentOpen = activeTab === "attachment";
  const isDateOpen = activeTab === "date";
  const isTimeOpen = activeTab === "time";

  const handleTabChange = (tab: TaskDetailTab) => {
    if (tab === "labels" && activeTab !== "labels") {
      setLabelsView("list");
    }
    onTabChange(tab);
  };

  const handleAddLabelClick = () => {
    setLabelsView("create");
    if (activeTab !== "labels") {
      onTabChange("labels");
    }
  };

  const handleAddUserClick = () => {
    if (activeTab !== "users") {
      onTabChange("users");
    }
  };

  const handleLabelToggle = (id: string) => {
    setSelectedLabelIds((prev) => {
      const next = new Set(prev);
      if (next.has(id)) {
        next.delete(id);
      } else {
        next.add(id);
      }
      return next;
    });
  };

  const handleUserToggle = (id: string) => {
    const effectiveTaskId = taskId || taskDetail?.id;
    if (!effectiveTaskId) return;

    const previous = selectedUserIds;
    const next = new Set(previous);
    if (next.has(id)) {
      next.delete(id);
    } else {
      next.add(id);
    }

    setSelectedUserIds(next);

    updateTask.mutate(
      { id: effectiveTaskId, params: { userIds: Array.from(next) } },
      {
        onSuccess: () => {
          toast(t("success"), 'success');
        },
        onError: (error: ErrorType) => {
          toast(error.response?.data?.error.message[0], 'error');
          setSelectedUserIds(previous);
        },
      },
    );
  };

  const handleCreate = (title: string, color: string) => {
    const effectiveTaskId = taskId || taskDetail?.id;
    if (!effectiveTaskId) return;

    createTaskRemark.mutate(
      { title, color, taskId: effectiveTaskId },
      {
        onSuccess: (response) => {
          const remark = response.data?.remark;
          if (remark?.id) {
            const newLabel: TaskLabel = {
              id: remark.id,
              title: remark.title,
              color: remark.color,
            };
            setLabels((prev) => [...prev, newLabel]);
            setSelectedLabelIds((prev) => new Set([...prev, newLabel.id]));
          }
          setLabelsView("list");
          toast(t("success"), 'success');
        },
        onError: (error: ErrorType) => {
          toast(error.response?.data?.error.message[0], 'error');
        },
      },
    );
  };

  const handleChecklistClose = () => {
    if (isChecklistOpen) onTabChange("checklist");
  };

  const handleChecklistCreate = (title: string) => {
    const effectiveTaskId = taskId || taskDetail?.id;
    if (!effectiveTaskId) return;

    createCheckListItem.mutate(
      { title, isDone: false, taskId: effectiveTaskId },
      {
        onSuccess: () => {
          handleChecklistClose();
          toast(t("success"), 'success');
        },
        onError: (error: ErrorType) => {
          toast(error.response?.data?.error.message[0], 'error');
        },
      },
    );
  };

  const handleAttachmentClose = () => {
    if (isAttachmentOpen) onTabChange("attachment");
  };

  const handleAttachmentCreate = async (data: { file?: File; title: string; linkId: string }) => {
    const effectiveTaskId = taskId || taskDetail?.id;
    if (!effectiveTaskId) return;

    let fileUrl = data.linkId.trim();

    if (data.file) {
      const formData = new FormData();
      formData.append("file", data.file);

      try {
        const uploadResult = await singleUpload.mutateAsync(formData);
        fileUrl = uploadResult?.data?.url ?? "";
      } catch (error) {
        toast((error as ErrorType).response?.data?.error.message[0], 'error');
        return;
      }
    }

    if (!fileUrl) return;

    const title = data.title.trim() || data.file?.name || "";
    const type = data.file ? "file" : "link";

    createTaskAttachment.mutate(
      { file: fileUrl, title, type, taskId: effectiveTaskId },
      {
        onSuccess: () => {
          handleAttachmentClose();
          toast(t("success"), 'success');
        },
        onError: (error: ErrorType) => {
          toast(error.response?.data?.error.message[0], 'error');
        },
      },
    );
  };

  const isAttachmentSubmitting = singleUpload.isPending || createTaskAttachment.isPending;

  const handleDateClose = () => {
    if (isDateOpen) onTabChange("date");
  };

  const handleDateSubmit = (data: { startDate: DateObject | null; endDate: DateObject | null }) => {
    const effectiveTaskId = taskId || taskDetail?.id;
    if (!effectiveTaskId) return;

    const previousStartDate = startDate;
    const previousEndDate = endDate;
    const params = {
      startDate: data.startDate ? toApiDate(data.startDate) : null,
      endDate: data.endDate ? toApiDate(data.endDate) : null,
    };

    setStartDate(data.startDate);
    setEndDate(data.endDate);

    updateTask.mutate(
      { id: effectiveTaskId, params },
      {
        onSuccess: () => {
          handleDateClose();
          toast(t("success"), 'success');
        },
        onError: (error: ErrorType) => {
          toast(error.response?.data?.error.message[0], 'error');
          setStartDate(previousStartDate);
          setEndDate(previousEndDate);
        },
      },
    );
  };

  return (
    <div className="relative">
      <TaskDetailActionBar
        activeTab={activeTab}
        onTabChange={handleTabChange}
        labelsPopover={
          isLabelsOpen ? (
            <TaskDetailLabelsPopover
              view={labelsView}
              labels={labels}
              selectedIds={selectedLabelIds}
              onViewChange={setLabelsView}
              onToggle={handleLabelToggle}
              onCreate={handleCreate}
              isSubmitting={createTaskRemark.isPending}
            />
          ) : null
        }
        usersPopover={
          isUsersOpen ? (
            <TaskDetailUsersPopover
              users={listUsers}
              selectedIds={selectedUserIds}
              onToggle={handleUserToggle}
              isLoading={isUsersPending}
              isSubmitting={updateTask.isPending}
              hasNextPage={hasNextUsersPage}
              isFetchingNextPage={isFetchingNextUsersPage}
              onLoadMore={() => {
                void fetchNextUsersPage();
              }}
              search={userSearch}
              onSearchChange={setUserSearch}
            />
          ) : null
        }
        checklistPopover={
          isChecklistOpen ? (
            <TaskDetailChecklistPopover
              onClose={handleChecklistClose}
              onSubmit={handleChecklistCreate}
              isSubmitting={createCheckListItem.isPending}
            />
          ) : null
        }
        attachmentPopover={
          isAttachmentOpen ? (
            <TaskDetailAttachmentPopover
              onClose={handleAttachmentClose}
              onSubmit={handleAttachmentCreate}
              isSubmitting={isAttachmentSubmitting}
            />
          ) : null
        }
        datePopover={
          isDateOpen ? (
            <TaskDetailDatePopover
              onClose={handleDateClose}
              onSubmit={handleDateSubmit}
              initialStartDate={startDate}
              initialEndDate={endDate}
              isSubmitting={updateTask.isPending}
            />
          ) : null
        }
        timePopover={isTimeOpen ? <TaskDetailTimePopover taskId={taskId} /> : null}
      />

      <TaskDetailMetadataPreview
        selectedLabels={selectedLabels}
        selectedUsers={selectedUsers}
        startDate={startDate}
        endDate={endDate}
        onAddLabel={handleAddLabelClick}
        onAddUser={handleAddUserClick}
      />
    </div>
  );
};

export default TaskDetailToolbar;
