import { useCallback, useEffect, useState } from "react";
import { cacheData, getCachedData } from "../slices/apiDataManager";
import ProjectRepository from "../repositories/ProjectRepository";
import { useProfile } from "./useProfile";
import { useDispatch, useSelector } from "react-redux";
import { setProjectId } from "../slices/localVariablesSlice";
import EmployeeList from "../components/Directory/EmployeeList";
import eventBus from "../services/eventBus";
import {
  Mutation,
  useMutation,
  useQuery,
  useQueryClient,
} from "@tanstack/react-query";
import showToast from "../services/toastService";


// ------------------------------Query-------------------

export const useProjects = () => {
  const loggedUser = useSelector((store) => store.globalVariables.loginUser);

  const {
    data: projects = [],
    isLoading: loading,
    error,
    refetch,
  } = useQuery({
    queryKey: ["ProjectsList"],
    queryFn: async () => {
      const response = await ProjectRepository.getProjectList();
      return response.data;
    },
    enabled: !!loggedUser,
  });

  return {
    projects,
    loading,
    error,
    refetch,
  };
};

export const useEmployeesByProjectAllocated = (selectedProject) => {
  const {
    data = [],
    isLoading,
    refetch,
    error,
  } = useQuery({
    queryKey: ["empListByProjectAllocated", selectedProject],
    queryFn: async () => {
      const res = await ProjectRepository.getProjectAllocation(selectedProject);
      return res.data || res;
    },
    enabled: !!selectedProject,
    onError: (error) => {
      showToast(
        error.message || "Error while Fetching project Allocated Employees",
        "error"
      );
    },
  });

  return {
    projectEmployees: data,
    loading: isLoading,
    error,
    refetch,
  };
};

export const useProjectDetails = (projectId, isAuto = true) => {
  const {
    data: projects_Details,
    isLoading,
    error,
    refetch,
  } = useQuery({
    queryKey: ["projectInfo", projectId],
    queryFn: async () => {
      const res = await ProjectRepository.getProjectByprojectId(projectId);
      return res.data || res;
    },
    enabled: !!projectId && isAuto,
    onError: (error) => {
      showToast(
        error.message || "Error while Fetching project Details",
        "error"
      );
    },
  });
  return { projects_Details, loading: isLoading, error, refetch };
};

export const useProjectsByEmployee = (employeeId) => {
  const {
    data: projectList = [],
    isLoading,
    error,
    refetch,
  } = useQuery({
    queryKey: ["ProjectsByEmployee", employeeId],
    queryFn: async () => {
      const res = await ProjectRepository.getProjectsByEmployee(employeeId);
      return res.data || res;
    },
    enabled: !!employeeId,
    onError: (error) => {
      showToast(
        error.message || "Error while Fetching project Employee",
        "error"
      );
    },
  });
  return { projectList, loading: isLoading, error, refetch };
};

export const useProjectsAllocationByEmployee = (employeeId) => {
  const {
    data: projectList = [],
    isLoading,
    error,
    refetch,
  } = useQuery({
    queryKey: ["ProjectsAllocationByEmployee", employeeId],
    queryFn: async () => {
      const res = await ProjectRepository.getProjectsAllocationByEmployee(
        employeeId
      );
      const sortedProjects = [...res.data].sort((a, b) =>
        a.projectName.localeCompare(b.projectName)
      );
      return sortedProjects || res;

      //return res.data || res;
    },
    enabled: !!employeeId,
    onError: (error) => {
      showToast(
        error.message || "Error while Fetching project Employee",
        "error"
      );
    },
  });
  return { projectList, loading: isLoading, error, refetch };
};

export const useProjectName = () => {
  const {
    data = [],
    isLoading,
    error,
    refetch,
    isError
  } = useQuery({
    queryKey: ["basicProjectNameList"],
    queryFn: async () => {
      const res = await ProjectRepository.projectNameList();
      return res.data || res;
    },
    onError: (error) => {
      showToast(error.message || "Error while Fetching project Name", "error");
    },
  });
  return { projectNames: data, loading: isLoading, Error: error, refetch,isError };
};

export const useProjectInfra = (projectId) => {
  const {
    data: projectInfra,
    isLoading,
    error,
  } = useQuery({
    queryKey: ["ProjectInfra", projectId],
    queryFn: async () => {
      const res = await ProjectRepository.getProjectInfraByproject(projectId);
      return res.data;
    },
    enabled: !!projectId,
    onError: (error) => {
      showToast(error.message || "Error while fetching project infra", "error");
    },
  });

  return { projectInfra, isLoading, error };
};

export const useProjectTasks = (workAreaId, IsExpandedArea = false) => {
  const {
    data: ProjectTaskList,
    isLoading,
    error,
  } = useQuery({
    queryKey: ["WorkItems", workAreaId],
    queryFn: async () => {
      const res = await ProjectRepository.getProjectTasksByWorkArea(workAreaId);
      return res.data;
    },
    enabled: !!workAreaId && !!IsExpandedArea,
    onError: (error) => {
      showToast(error.message || "Error while Fetching project Tasks", "error");
    },
  });
  return { ProjectTaskList, isLoading, error };
};

export const useProjectTasksByEmployee = (
  employeeId,
  fromDate,
  toDate,
) => {

  return useQuery({
    queryKey: ["TasksByEmployee", employeeId],
    queryFn: async () => {
      const res = await ProjectRepository.getProjectTasksByEmployee(
        employeeId,
        fromDate,
        toDate
      );
      return res.data;
    },
    enabled: !!employeeId && !!fromDate && !!toDate,
    onError: (error) => {
      showToast(error.message || "Error while Fetching project Tasks", "error");
    },
  });
};

// -- -------------Mutation-------------------------------

export const useCreateProject = ({ onSuccessCallback }) => {
  const queryClient = useQueryClient();

  return useMutation({
    mutationFn: async (newProject) => {
      const res = await ProjectRepository.manageProject(newProject);
      return res.data;
    },
    onSuccess: (data) => {
      //  Invalidate the cache
      queryClient.invalidateQueries({ queryKey: ["ProjectsList"] });
      queryClient.invalidateQueries({ queryKey: ["basicProjectNameList"] });

      //  Emit event for consumers (like useProjects or others)
      eventBus.emit("project", {
        keyword: "Create_Project",
        response: data,
      });

      showToast("Project Created successfully.", "success");

      if (onSuccessCallback) {
        onSuccessCallback(data);
      }
    },
    onError: (error) => {
      showToast(error.message || "Error while creating project", "error");
    },
  });
};

export const useUpdateProject = ({ onSuccessCallback }) => {
  const queryClient = useQueryClient();
  const { mutate, isPending, isSuccess, isError } = useMutation({
    mutationFn: async ({ projectId, updatedData }) => {
      return await ProjectRepository.updateProject(projectId, updatedData);
    },

    onSuccess: (data, variables) => {
      const { projectId } = variables;

      queryClient.invalidateQueries({ queryKey: ["ProjectsList"] });
      queryClient.invalidateQueries({ queryKey: ["projectInfo", projectId] });
      queryClient.invalidateQueries({ queryKey: ["basicProjectNameList"] });

      eventBus.emit("project", {
        keyword: "Update_Project",
        response: data,
      });

      showToast("Project updated successfully.", "success");

      if (onSuccessCallback) {
        onSuccessCallback(data);
      }
    },

    onError: (error) => {
      console.log(error);
      showToast(error?.message || "Error while updating project", "error");
    },
  });

  return {
    mutate,
    isPending,
    isSuccess,
    isError,
  };
};

export const useManageProjectInfra = ({ onSuccessCallback }) => {
  const queryClient = useQueryClient();
  return useMutation({
    mutationFn: async ({ infraObject, projectId }) => {
      return await ProjectRepository.manageProjectInfra(infraObject);
    },
    onSuccess: (data, variables) => {
      const { projectId } = variables;
      queryClient.invalidateQueries({ queryKey: ["ProjectInfra", projectId] });
      if (onSuccessCallback) onSuccessCallback(data, variables);
    },
    onError: (error) => {
      showToast(error.message || "Failed to update Project Infra", "error");
    },
  });
};

export const useManageProjectAllocation = ({
  onSuccessCallback,
  onErrorCallback,
}) => {
  const queryClient = useQueryClient();

  const { mutate, isPending, isSuccess, isError } = useMutation({
    mutationFn: async ({ items }) => {
      const response = await ProjectRepository.manageProjectAllocation(items);
      return response.data;
    },
    onSuccess: (data, variables, context) => {
      queryClient.invalidateQueries({
        queryKey: ["empListByProjectAllocated"],
      });
      queryClient.removeQueries({ queryKey: ["projectEmployees"] });
      if (variables?.added) {
        showToast("Employee Assigned Successfully", "success");
      } else {
        showToast("Removed Employee Successfully", "success");
      }

      if (onSuccessCallback) onSuccessCallback(data, context);
    },
    onError: (error) => {
      const message =
        error?.response?.data?.message ||
        error.message ||
        "Error occurred during API call";
      showToast(message, "error");
      if (onErrorCallback) onErrorCallback(error);
    },
  });

  return {
    mutate,
    isPending,
    isSuccess,
    isError,
  };
};

export const useManageTask = ({ onSuccessCallback }) => {
  const queryClient = useQueryClient();
  const selectedProject = useSelector(
    (store) => store.localVariables.projectId
  );
  return useMutation({
    mutationFn: async ({
      payload,
      PreviousPlannedWork,
      previousCompletedWork,
      buildingId,
      floorId,
      workAreaId,
    }) => await ProjectRepository.manageProjectTasks(payload),
    onSuccess: (data, variables) => {
      const {
        workAreaId,
        buildingId,
        floorId,
        PreviousPlannedWork,
        previousCompletedWork,
      } = variables;
      queryClient.invalidateQueries({ queryKey: ["WorkItems"] });
      const getPlannedDelta = (previous, current) => current - previous;
      queryClient.setQueryData(["ProjectInfra", selectedProject], (oldData) => {
        if (!oldData) return oldData;
        const { workAreaId, floorId, buildingId } = variables;
        const updatedData = JSON.parse(JSON.stringify(oldData));
        return updatedData.map((building) => {
          if (building.id !== buildingId) return building;
          return {
            ...building,
            floors: building.floors.map((floor) => {
              if (floor.id !== floorId) return floor;

              return {
                ...floor,
                workAreas: floor.workAreas.map((area) => {
                  if (area.id !== workAreaId) return area;

                  const previousPlanned = PreviousPlannedWork ?? 0;
                  const currentPlanned =
                    data?.data[0]?.workItem.plannedWork ?? 0;

                  const plannedWorkDelta = getPlannedDelta(
                    previousPlanned,
                    currentPlanned
                  );
                  const updatedPlannedWork =
                    (area.plannedWork ?? 0) + plannedWorkDelta;
                  const previousCompleted = previousCompletedWork;

                  const currentCompleted =
                    data?.data[0]?.workItem.completedWork ?? 0;
                  const completedWorkDelta = getPlannedDelta(
                    previousCompleted,
                    currentCompleted
                  );
                  const updatedCompletedWork =
                    (area.completedWork ?? 0) + completedWorkDelta;
                  return {
                    ...area,
                    plannedWork: updatedPlannedWork,
                    completedWork: updatedCompletedWork,
                  };
                }),
              };
            }),
          };
        });
      });

      queryClient.setQueryData(["ProjectsList"], (projects) => {
        if (!projects) return projects;

        return projects.map((project) => {
          if (project.id !== selectedProject) return project;

          const previousPlanned = PreviousPlannedWork ?? 0;
          const currentPlanned = data?.data[0]?.workItem.plannedWork ?? 0;

          const plannedWorkDelta = getPlannedDelta(
            previousPlanned,
            currentPlanned
          );
          const updatedPlannedWork =
            (project.plannedWork ?? 0) + plannedWorkDelta;
          const previousCompleted = previousCompletedWork;
          const currentCompleted = data?.data[0]?.workItem.completedWork ?? 0;
          const completedWorkDelta = getPlannedDelta(
            previousCompleted,
            currentCompleted
          );
          const updatedCompletedWork =
            (project.completedWork ?? 0) + completedWorkDelta;
          return {
            ...project,
            plannedWork: updatedPlannedWork,
            completedWork: updatedCompletedWork,
          };
        });
      });
      if (onSuccessCallback) onSuccessCallback(data);
    },
    onError: (error) => {
      const message =
        error?.response?.data?.message ||
        error.message ||
        "Error occurred during API call";
      showToast(message, "error");
    },
  });
};

export const useDeleteProjectTask = (onSuccessCallback) => {
  const queryClient = useQueryClient();
  const selectedProject = useSelector(
    (store) => store.localVariables.projectId
  );
  return useMutation({
    mutationFn: async ({
      workItemId,
      workAreaId,
      completedTask,
      plannedTask,
    }) => {
      return await ProjectRepository.deleteProjectTask(workItemId);
    },
    onSuccess: (_, variables) => {
      const { completedTask, plannedTask, workAreaId, buildingId, floorId } =
        variables;

      queryClient.invalidateQueries({
        queryKey: ["WorkItems", variables.workAreaId],
      });

      queryClient.setQueryData(["ProjectInfra", selectedProject], (oldData) => {
        if (!oldData) return oldData;

        const { workAreaId, floorId, buildingId, plannedTask, completedTask } =
          variables;

        const updatedData = JSON.parse(JSON.stringify(oldData));

        return updatedData.map((building) => {
          if (building.id !== buildingId) return building;

          return {
            ...building,
            floors: building.floors.map((floor) => {
              if (floor.id !== floorId) return floor;

              return {
                ...floor,
                workAreas: floor.workAreas.map((area) => {
                  if (area.id !== workAreaId) return area;

                  return {
                    ...area,
                    plannedWork: (area.plannedWork ?? 0) - plannedTask,
                    completedWork: (area.completedWork ?? 0) - completedTask,
                  };
                }),
              };
            }),
          };
        });
      });

      queryClient.setQueryData(["ProjectsList"], (projects) => {
        if (!projects) return projects;

        return projects.map((project) => {
          if (project.id !== selectedProject) return project;

          return {
            ...project,
            plannedWork: (project.plannedWork ?? 0) - plannedTask,
            completedWork: (project.completedWork ?? 0) - completedTask,
          };
        });
      });
      showToast("Task deleted successfully", "success");
      if (onSuccessCallback) onSuccessCallback();
    },
    onError: (error) => {
      showToast(
        error?.response?.data?.message ||
          error.message ||
          "Failed to delete task",
        "error"
      );
      if (onSuccessCallback) onSuccessCallback();
    },
  });
};
