import { useCallback, useEffect, useRef, useState } from "react";

import {
  fetchObservationWorkspaceLayoutProfile,
  saveObservationWorkspaceLayoutProfile,
  WorkspaceLayoutApiError,
  type ObservationWorkspaceLayoutProfile,
} from "./workspaceLayout";

export type WorkspaceLayoutProfileState =
  | "idle"
  | "loading"
  | "ready"
  | "saving"
  | "error"
  | "conflict";

export interface WorkspaceLayoutProfileController {
  profile: ObservationWorkspaceLayoutProfile | null;
  state: WorkspaceLayoutProfileState;
  error: string | null;
  refresh: () => Promise<ObservationWorkspaceLayoutProfile | null>;
  save: (
    profile: ObservationWorkspaceLayoutProfile,
  ) => Promise<ObservationWorkspaceLayoutProfile | null>;
}

function errorMessage(error: unknown): string {
  return error instanceof Error && error.message.trim()
    ? error.message
    : "Операция с профилем рабочей поверхности завершилась ошибкой.";
}

export function useWorkspaceLayoutProfile(): WorkspaceLayoutProfileController {
  const [profile, setProfile] = useState<ObservationWorkspaceLayoutProfile | null>(null);
  const profileRef = useRef<ObservationWorkspaceLayoutProfile | null>(null);
  const [state, setState] = useState<WorkspaceLayoutProfileState>("idle");
  const [error, setError] = useState<string | null>(null);
  const mounted = useRef(true);
  const requestSequence = useRef(0);
  const saveInFlight = useRef(false);

  const commitProfile = useCallback((next: ObservationWorkspaceLayoutProfile | null) => {
    profileRef.current = next;
    setProfile(next);
  }, []);

  const refresh = useCallback(async () => {
    const sequence = ++requestSequence.current;
    setState("loading");
    setError(null);
    try {
      const loaded = await fetchObservationWorkspaceLayoutProfile();
      if (!mounted.current || sequence !== requestSequence.current) return null;
      commitProfile(loaded);
      setState("ready");
      return loaded;
    } catch (loadError) {
      if (!mounted.current || sequence !== requestSequence.current) return null;
      setState("error");
      setError(errorMessage(loadError));
      return null;
    }
  }, [commitProfile]);

  useEffect(() => {
    mounted.current = true;
    void refresh();
    return () => {
      mounted.current = false;
      requestSequence.current += 1;
    };
  }, [refresh]);

  useEffect(() => {
    if (state !== "error") return;
    // The desktop shell can become ready before its loopback API. Keep the
    // last-layout restore self-healing instead of requiring a page reload once
    // the local service finishes starting.
    const timer = window.setTimeout(() => void refresh(), 5_000);
    return () => window.clearTimeout(timer);
  }, [refresh, state]);

  useEffect(() => {
    const refreshAfterNetworkRecovery = () => void refresh();
    window.addEventListener("online", refreshAfterNetworkRecovery);
    return () => window.removeEventListener("online", refreshAfterNetworkRecovery);
  }, [refresh]);

  const save = useCallback(async (draft: ObservationWorkspaceLayoutProfile) => {
    if (saveInFlight.current) return null;
    const current = profileRef.current;
    if (current && draft.revision !== current.revision) {
      setState("conflict");
      setError("Профиль изменился после открытия. Обновите данные перед сохранением.");
      return null;
    }
    saveInFlight.current = true;
    setState("saving");
    setError(null);
    try {
      const saved = await saveObservationWorkspaceLayoutProfile(draft);
      if (!mounted.current) return null;
      commitProfile(saved);
      setState("ready");
      return saved;
    } catch (saveError) {
      if (!mounted.current) return null;
      const conflict = saveError instanceof WorkspaceLayoutApiError && saveError.conflict;
      setState(conflict ? "conflict" : "error");
      setError(errorMessage(saveError));
      return null;
    } finally {
      saveInFlight.current = false;
    }
  }, [commitProfile]);

  return { profile, state, error, refresh, save };
}
