"use client";

import React, {
  createContext,
  useCallback,
  useContext,
  useMemo,
  useSyncExternalStore,
} from "react";

interface ProjectContextType {
  isHydrated: boolean;
  projectId: string;
  projectName: string;
  projectNameTranslations?: {
    ar: string;
    en: string;
  };
  projectProgress: number;
  setProject: (
    id: string,
    name: string,
    progress: number,
    translations?: { ar: string; en: string },
  ) => void;
  clearProject: () => void;
  updateProgress: (progress: number) => void;
}

const ProjectContext = createContext<ProjectContextType | undefined>(undefined);

type StoredProjectSnapshot = {
  id: string;
  name: string;
  translations?: {
    ar: string;
    en: string;
  };
  progress: number;
  isHydrated: boolean;
};

const EMPTY_PROJECT_SNAPSHOT: StoredProjectSnapshot = {
  id: "",
  name: "",
  translations: undefined,
  progress: 0,
  isHydrated: false,
};

let currentProjectSnapshot = EMPTY_PROJECT_SNAPSHOT;
let hasLoadedProjectSnapshot = false;

const projectStoreListeners = new Set<() => void>();

function readStoredProject(): StoredProjectSnapshot {
  if (typeof window === "undefined") {
    return EMPTY_PROJECT_SNAPSHOT;
  }

  const id = sessionStorage.getItem("project_id") || "";
  const name = sessionStorage.getItem("project_name") || "";
  const translationsValue = sessionStorage.getItem("project_name_translations");
  const progress = parseInt(sessionStorage.getItem("project_progress") || "0", 10);

  let translations: StoredProjectSnapshot["translations"];

  if (translationsValue) {
    try {
      translations = JSON.parse(translationsValue);
    } catch (error) {
      console.error("Failed to parse project translations", error);
    }
  }

  return {
    id,
    name,
    translations,
    progress,
    isHydrated: true,
  };
}

function writeStoredProject(snapshot: StoredProjectSnapshot) {
  if (typeof window === "undefined") {
    return;
  }

  if (!snapshot.id) {
    sessionStorage.removeItem("project_id");
    sessionStorage.removeItem("project_name");
    sessionStorage.removeItem("project_name_translations");
    sessionStorage.removeItem("project_progress");
    return;
  }

  sessionStorage.setItem("project_id", snapshot.id);
  sessionStorage.setItem("project_name", snapshot.name);

  if (snapshot.translations) {
    sessionStorage.setItem(
      "project_name_translations",
      JSON.stringify(snapshot.translations),
    );
  } else {
    sessionStorage.removeItem("project_name_translations");
  }

  sessionStorage.setItem("project_progress", String(snapshot.progress));
}

function emitProjectStoreChange() {
  projectStoreListeners.forEach((listener) => listener());
}

function setProjectSnapshot(snapshot: StoredProjectSnapshot) {
  currentProjectSnapshot = snapshot;
  hasLoadedProjectSnapshot = true;
  writeStoredProject(snapshot);
  emitProjectStoreChange();
}

function subscribeToProjectStore(listener: () => void) {
  projectStoreListeners.add(listener);
  return () => {
    projectStoreListeners.delete(listener);
  };
}

function getProjectSnapshot() {
  if (!hasLoadedProjectSnapshot && typeof window !== "undefined") {
    currentProjectSnapshot = readStoredProject();
    hasLoadedProjectSnapshot = true;
  }

  return currentProjectSnapshot;
}

function getProjectServerSnapshot() {
  return EMPTY_PROJECT_SNAPSHOT;
}

export function ProjectProvider({ children }: { children: React.ReactNode }) {
  const projectSnapshot = useSyncExternalStore(
    subscribeToProjectStore,
    getProjectSnapshot,
    getProjectServerSnapshot,
  );

  const clearProject = useCallback(() => {
    setProjectSnapshot(EMPTY_PROJECT_SNAPSHOT);
  }, []);

  const setProject = useCallback((
    id: string,
    name: string,
    progress: number,
    translations?: { ar: string; en: string },
  ) => {
    const normalizedId = id.trim();

    if (!normalizedId) {
      clearProject();
      return;
    }

    const currentSnapshot = getProjectSnapshot();
    const nextTranslations =
      translations ??
      (currentSnapshot.id === normalizedId
        ? currentSnapshot.translations
        : undefined);

    setProjectSnapshot({
      id: normalizedId,
      name,
      translations: nextTranslations,
      progress,
      isHydrated: true,
    });
  }, [clearProject]);

  const updateProgress = useCallback((progress: number) => {
    setProjectSnapshot({
      ...getProjectSnapshot(),
      progress,
    });
  }, []);

  const value = useMemo(
    () => ({
      isHydrated: projectSnapshot.isHydrated,
      projectId: projectSnapshot.id,
      projectName: projectSnapshot.name,
      projectNameTranslations: projectSnapshot.translations,
      projectProgress: projectSnapshot.progress,
      setProject,
      clearProject,
      updateProgress,
    }),
    [clearProject, projectSnapshot, setProject, updateProgress],
  );

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

export function useProject() {
  const context = useContext(ProjectContext);
  if (!context) {
    throw new Error("useProject must be used within ProjectProvider");
  }
  return context;
}
