

import { observer } from "mobx-react";
import type { ReactNode } from "react";
import { useEffect, useState } from "react";
import useSWR from "swr";
// buzzwareTech imports
import { EUserPermissions, EUserPermissionsLevel } from "@buzzwaretech/constants";
import { GANTT_TIMELINE_TYPE } from "@buzzwaretech/types";
// components
import { ProjectAccessRestriction } from "@/components/auth-screens/project/project-access-restriction";
import {
    PROJECT_ALL_CYCLES,
    PROJECT_DETAILS,
    PROJECT_ESTIMATES,
    PROJECT_INTAKE_STATE,
    PROJECT_LABELS,
    PROJECT_MEMBERS,
    PROJECT_MEMBER_PREFERENCES,
    PROJECT_ME_INFORMATION,
    PROJECT_MODULES,
    PROJECT_STATES,
    PROJECT_VIEWS,
} from "@/constants/fetch-keys";
// hooks
import { useProjectEstimates } from "@/hooks/store/estimates";
import { useCycle } from "@/hooks/store/use-cycle";
import { useLabel } from "@/hooks/store/use-label";
import { useMember } from "@/hooks/store/use-member";
import { useModule } from "@/hooks/store/use-module";
import { useProject } from "@/hooks/store/use-project";
import { useProjectState } from "@/hooks/store/use-project-state";
import { useProjectView } from "@/hooks/store/use-project-view";
import { useUser, useUserPermissions } from "@/hooks/store/user";
import { useTimeLineChart } from "@/hooks/use-timeline-chart";

interface IProjectAuthWrapper {
  workspaceSlug: string;
  projectId: string;
  children: ReactNode;
  isLoading?: boolean;
}

export const ProjectAuthWrapper = observer(function ProjectAuthWrapper(
  props: IProjectAuthWrapper,
) {
  const {
    workspaceSlug,
    projectId,
    children,
    isLoading: isParentLoading = false,
  } = props;
  // states
  const [isJoiningProject, setIsJoiningProject] = useState(false);
  // store hooks
  const {
    fetchUserProjectInfo,
    allowPermissions,
    getProjectRoleByWorkspaceSlugAndProjectId,
  } = useUserPermissions();
  const { fetchProjectDetails } = useProject();
  const { joinProject } = useUserPermissions();
  const { fetchAllCycles } = useCycle();
  const { fetchModulesSlim, fetchModules } = useModule();
  const { initGantt } = useTimeLineChart(GANTT_TIMELINE_TYPE.MODULE);
  const { fetchViews } = useProjectView();
  const {
    project: { fetchProjectMembers, fetchProjectUserProperties },
  } = useMember();
  const { fetchProjectStates, fetchProjectIntakeState } = useProjectState();
  const { data: currentUserData } = useUser();
  const { fetchProjectLabels } = useLabel();
  const { getProjectEstimates } = useProjectEstimates();
  // derived values
  const hasPermissionToCurrentProject = allowPermissions(
    [EUserPermissions.ADMIN, EUserPermissions.MEMBER, EUserPermissions.GUEST],
    EUserPermissionsLevel.PROJECT,
    workspaceSlug,
    projectId,
  );
  const currentProjectRole = getProjectRoleByWorkspaceSlugAndProjectId(
    workspaceSlug,
    projectId,
  );
  const isWorkspaceAdmin = allowPermissions(
    [EUserPermissions.ADMIN],
    EUserPermissionsLevel.WORKSPACE,
    workspaceSlug,
  );
  // Initialize module timeline chart
  useEffect(() => {
    initGantt();
    // eslint-disable-next-line react-hooks/exhaustive-deps
  }, []);

  // fetching project details
  const { isLoading: isProjectDetailsLoading, error: projectDetailsError } =
    useSWR(PROJECT_DETAILS(workspaceSlug, projectId), () =>
      fetchProjectDetails(workspaceSlug, projectId),
    );
  // fetching user project member information
  useSWR(PROJECT_ME_INFORMATION(workspaceSlug, projectId), () =>
    fetchUserProjectInfo(workspaceSlug, projectId),
  );
  // fetching project member preferences
  useSWR(
    currentUserData?.id
      ? PROJECT_MEMBER_PREFERENCES(projectId, currentProjectRole)
      : null,
    currentUserData?.id
      ? () => fetchProjectUserProperties(workspaceSlug, projectId)
      : null,
    { revalidateIfStale: false, revalidateOnFocus: false },
  );
  // fetching project labels
  useSWR(
    PROJECT_LABELS(projectId, currentProjectRole),
    () => fetchProjectLabels(workspaceSlug, projectId),
    {
      revalidateIfStale: false,
      revalidateOnFocus: false,
    },
  );
  // fetching project members
  useSWR(
    PROJECT_MEMBERS(projectId, currentProjectRole),
    () => fetchProjectMembers(workspaceSlug, projectId),
    {
      revalidateIfStale: false,
      revalidateOnFocus: false,
    },
  );
  // fetching project states
  useSWR(
    PROJECT_STATES(projectId, currentProjectRole),
    () => fetchProjectStates(workspaceSlug, projectId),
    {
      revalidateIfStale: false,
      revalidateOnFocus: false,
    },
  );
  // fetching project intake state
  useSWR(
    PROJECT_INTAKE_STATE(projectId, currentProjectRole),
    () => fetchProjectIntakeState(workspaceSlug, projectId),
    {
      revalidateIfStale: false,
      revalidateOnFocus: false,
    },
  );
  // fetching project estimates
  useSWR(
    PROJECT_ESTIMATES(projectId, currentProjectRole),
    () => getProjectEstimates(workspaceSlug, projectId),
    {
      revalidateIfStale: false,
      revalidateOnFocus: false,
    },
  );
  // fetching project cycles
  useSWR(
    PROJECT_ALL_CYCLES(projectId, currentProjectRole),
    () => fetchAllCycles(workspaceSlug, projectId),
    {
      revalidateIfStale: false,
      revalidateOnFocus: false,
    },
  );
  // fetching project modules
  useSWR(
    PROJECT_MODULES(projectId, currentProjectRole),
    async () => {
      await Promise.all([
        fetchModulesSlim(workspaceSlug, projectId),
        fetchModules(workspaceSlug, projectId),
      ]);
    },
    { revalidateIfStale: false, revalidateOnFocus: false },
  );
  // fetching project views
  useSWR(
    PROJECT_VIEWS(projectId, currentProjectRole),
    () => fetchViews(workspaceSlug, projectId),
    {
      revalidateIfStale: false,
      revalidateOnFocus: false,
    },
  );

  // handle join project
  const handleJoinProject = () => {
    setIsJoiningProject(true);
    joinProject(workspaceSlug, projectId).finally(() =>
      setIsJoiningProject(false),
    );
  };

  const isProjectLoading =
    (isParentLoading || isProjectDetailsLoading) && !projectDetailsError;

  if (isProjectLoading) return null;

  if (!isProjectLoading && hasPermissionToCurrentProject === false) {
    return (
      <ProjectAccessRestriction
        errorStatusCode={projectDetailsError?.status}
        isWorkspaceAdmin={isWorkspaceAdmin}
        handleJoinProject={handleJoinProject}
        isJoinButtonDisabled={isJoiningProject}
      />
    );
  }

  return <>{children}</>;
});
