import { useEffect, useMemo } from 'react';
import { isNonEmptyArray } from '@sniptt/guards';
import { DateTime } from 'luxon';
import { useRecoilState } from 'recoil';

import { useActivities } from '@/activities/hooks/useActivities';
import { currentCompletedTaskQueryVariablesState } from '@/activities/tasks/states/currentCompletedTaskQueryVariablesState';
import { currentIncompleteTaskQueryVariablesState } from '@/activities/tasks/states/currentIncompleteTaskQueryVariablesState';
import { FIND_MANY_TIMELINE_ACTIVITIES_ORDER_BY } from '@/activities/timeline/constants/FindManyTimelineActivitiesOrderBy';
import { Activity } from '@/activities/types/Activity';
import { ActivityTargetableObject } from '@/activities/types/ActivityTargetableEntity';
import { useFilterDropdown } from '@/object-record/object-filter-dropdown/hooks/useFilterDropdown';
import { ObjectRecordQueryVariables } from '@/object-record/types/ObjectRecordQueryVariables';
import { parseDate } from '~/utils/date-utils';
import { isDeeplyEqual } from '~/utils/isDeeplyEqual';

type UseTasksProps = {
  filterDropdownId?: string;
  targetableObjects: ActivityTargetableObject[];
};

export const useTasks = ({
  targetableObjects,
  filterDropdownId,
}: UseTasksProps) => {
  const { selectedFilter } = useFilterDropdown({
    filterDropdownId,
  });

  const assigneeIdFilter = useMemo(
    () =>
      selectedFilter
        ? {
            assigneeId: {
              in: JSON.parse(selectedFilter.value),
            },
          }
        : undefined,
    [selectedFilter],
  );

  const skipActivityTargets = !isNonEmptyArray(targetableObjects);

  const completedQueryVariables = useMemo(
    () =>
      ({
        filter: {
          completedAt: { is: 'NOT_NULL' },
          type: { eq: 'Task' },
          ...assigneeIdFilter,
        },
        orderBy: FIND_MANY_TIMELINE_ACTIVITIES_ORDER_BY,
      }) as ObjectRecordQueryVariables,
    [assigneeIdFilter],
  );

  const incompleteQueryVariables = useMemo(
    () =>
      ({
        filter: {
          completedAt: { is: 'NULL' },
          type: { eq: 'Task' },
          ...assigneeIdFilter,
        },
        orderBy: FIND_MANY_TIMELINE_ACTIVITIES_ORDER_BY,
      }) as ObjectRecordQueryVariables,
    [assigneeIdFilter],
  );

  const [
    currentCompletedTaskQueryVariables,
    setCurrentCompletedTaskQueryVariables,
  ] = useRecoilState(currentCompletedTaskQueryVariablesState);

  const [
    currentIncompleteTaskQueryVariables,
    setCurrentIncompleteTaskQueryVariables,
  ] = useRecoilState(currentIncompleteTaskQueryVariablesState);

  // TODO: fix useEffect, remove with better pattern
  useEffect(() => {
    if (
      !isDeeplyEqual(
        completedQueryVariables,
        currentCompletedTaskQueryVariables,
      )
    ) {
      setCurrentCompletedTaskQueryVariables(completedQueryVariables);
    }
  }, [
    completedQueryVariables,
    currentCompletedTaskQueryVariables,
    setCurrentCompletedTaskQueryVariables,
  ]);

  useEffect(() => {
    if (
      !isDeeplyEqual(
        incompleteQueryVariables,
        currentIncompleteTaskQueryVariables,
      )
    ) {
      setCurrentIncompleteTaskQueryVariables(incompleteQueryVariables);
    }
  }, [
    incompleteQueryVariables,
    currentIncompleteTaskQueryVariables,
    setCurrentIncompleteTaskQueryVariables,
  ]);

  const {
    activities: completeTasksData,
    initialized: initializedCompleteTasks,
  } = useActivities({
    targetableObjects,
    activitiesFilters: completedQueryVariables.filter ?? {},
    activitiesOrderByVariables: completedQueryVariables.orderBy ?? {},
    skipActivityTargets,
  });

  const {
    activities: incompleteTaskData,
    initialized: initializedIncompleteTasks,
  } = useActivities({
    targetableObjects,
    activitiesFilters: incompleteQueryVariables.filter ?? {},
    activitiesOrderByVariables: incompleteQueryVariables.orderBy ?? {},
    skipActivityTargets,
  });

  const todayOrPreviousTasks = incompleteTaskData?.filter((task) => {
    if (!task.dueAt) {
      return false;
    }
    const dueDate = parseDate(task.dueAt).toJSDate();
    const today = DateTime.now().endOf('day').toJSDate();
    return dueDate <= today;
  });

  const upcomingTasks = incompleteTaskData?.filter((task) => {
    if (!task.dueAt) {
      return false;
    }
    const dueDate = parseDate(task.dueAt).toJSDate();
    const today = DateTime.now().endOf('day').toJSDate();
    return dueDate > today;
  });

  const unscheduledTasks = incompleteTaskData?.filter((task) => {
    return !task.dueAt;
  });

  const completedTasks = completeTasksData;

  return {
    todayOrPreviousTasks: (todayOrPreviousTasks ?? []) as Activity[],
    upcomingTasks: (upcomingTasks ?? []) as Activity[],
    unscheduledTasks: (unscheduledTasks ?? []) as Activity[],
    completedTasks: (completedTasks ?? []) as Activity[],
    initialized: initializedCompleteTasks && initializedIncompleteTasks,
  };
};
