"use client";

import { useSession } from "next-auth/react";
import { usePathname, useRouter } from "next/navigation";
import React, {
  createContext,
  useCallback,
  useContext,
  useEffect,
  useState,
} from "react";

import { ProjectSelector } from "@/components/project/ProjectSelector";
import {
  config,
  NETWORK_NAME,
  setMapExtent,
  setMapWorkspace,
  setNetworkName,
} from "@/config/config";
import { apiFetch } from "@/lib/apiFetch";
import { permissionCodes } from "@/lib/permissions";
import { useAccessStore } from "@/store/accessStore";
import { useProjectStore } from "@/store/projectStore";

interface ProjectContextType {
  workspace: string;
  networkName: string;
  extent: number[];
}

const ProjectContext = createContext<ProjectContextType | undefined>(undefined);
const MAP_WORKSPACE_STORAGE_KEY = "MAP_WORKSPACE";
const NETWORK_NAME_STORAGE_KEY = "NETWORK_NAME";
const MAP_EXTENT_STORAGE_KEY = "MAP_EXTENT";

export const ProjectProvider: React.FC<{ children: React.ReactNode }> = ({
  children,
}) => {
  const { status } = useSession();
  const pathname = usePathname();
  const router = useRouter();
  const canManageEnvironment = useAccessStore((state) =>
    state.permissions.includes(permissionCodes.environmentManage),
  );
  const [isConfigured, setIsConfigured] = useState(false);
  const setCurrentProjectId = useProjectStore(
    (state) => state.setCurrentProjectId,
  );
  const [currentProject, setCurrentProject] = useState({
    workspace: config.MAP_WORKSPACE,
    networkName: NETWORK_NAME || "tjwater",
    extent: config.MAP_EXTENT,
  });

  const applyConfig = useCallback(
    async (
      projectId: string,
      workspace: string,
      networkName: string,
      extent: number[],
    ) => {
      const resolvedProjectId = projectId || networkName || workspace;
      setMapWorkspace(workspace);
      setNetworkName(networkName);
      setMapExtent(extent);
      localStorage.setItem(MAP_WORKSPACE_STORAGE_KEY, workspace);
      localStorage.setItem(NETWORK_NAME_STORAGE_KEY, networkName);
      localStorage.setItem(MAP_EXTENT_STORAGE_KEY, extent.join(","));
      localStorage.removeItem(`${workspace}_map_view`);
      setCurrentProject({ workspace, networkName, extent });
      setCurrentProjectId(resolvedProjectId);
      setIsConfigured(true);

      try {
        const openResponse = await apiFetch(
          `${config.BACKEND_URL}/api/v1/projects/current`,
          { method: "POST" },
        );
        if (!openResponse.ok) {
          throw new Error(`Failed to open project: HTTP ${openResponse.status}`);
        }

        const infoResponse = await apiFetch(
          `${config.BACKEND_URL}/api/v1/projects/current`,
        );
        if (!infoResponse.ok) {
          console.warn(
            `Failed to fetch project info: HTTP ${infoResponse.status}`,
          );
          return;
        }

        const data = await infoResponse.json();
        if (data?.gs_workspace && data.gs_workspace !== workspace) {
          setMapWorkspace(data.gs_workspace);
          localStorage.setItem(MAP_WORKSPACE_STORAGE_KEY, data.gs_workspace);
          setCurrentProject((previous) => ({
            ...previous,
            workspace: data.gs_workspace,
          }));
        }

        const bbox = Array.isArray(data?.map_extent?.bbox)
          ? data.map_extent.bbox.map((value: number) => Number(value))
          : null;
        if (bbox?.length === 4) {
          setMapExtent(bbox);
          localStorage.setItem(MAP_EXTENT_STORAGE_KEY, bbox.join(","));
          localStorage.removeItem(`${workspace}_map_view`);
          setCurrentProject((previous) => ({ ...previous, extent: bbox }));
        }
      } catch (error) {
        console.error("Failed to setup project:", error);
      }
    },
    [setCurrentProjectId],
  );

  useEffect(() => {
    if (status !== "authenticated") {
      return;
    }

    // Check localStorage
    const savedWorkspace = localStorage.getItem(MAP_WORKSPACE_STORAGE_KEY);
    const savedNetwork = localStorage.getItem(NETWORK_NAME_STORAGE_KEY);
    const savedExtent = localStorage.getItem(MAP_EXTENT_STORAGE_KEY);
    const savedProjectId = localStorage.getItem("active_project");

    // If we have saved config, use it.
    if (savedWorkspace && savedNetwork) {
      applyConfig(
        savedProjectId || savedNetwork || savedWorkspace,
        savedWorkspace,
        savedNetwork,
        savedExtent ? savedExtent.split(",").map(Number) : config.MAP_EXTENT,
      );
    }
  }, [applyConfig, status]);

  const isGlobalManagementRoute =
    pathname.startsWith("/system-admin") || pathname.startsWith("/audit-logs");

  if (status === "authenticated" && !isConfigured && !isGlobalManagementRoute) {
    return (
      <ProjectSelector
        open={true}
        onClose={
          canManageEnvironment ? () => router.push("/system-admin") : undefined
        }
        onSelect={(projectId, ws, net, extent) =>
          applyConfig(projectId, ws, net, extent)
        }
      />
    );
  }

  return (
    <ProjectContext.Provider value={currentProject}>
      {children}
    </ProjectContext.Provider>
  );
};

export const useProject = () => useContext(ProjectContext);
