import { useCallback, useEffect, useState } from 'react';
import {
  createInitialLayout,
  getVisiblePanels,
  insertAtEdge,
  loadWorkspaceLayouts,
  resetLayout,
  saveWorkspaceLayouts,
  setPanelVisible,
  updateSplitRatio,
  validateLayout,
  WORKSPACE_IDS,
} from './layoutEngine';

const MIN_RATIO = 0.15;
const MAX_RATIO = 0.85;
const ACTIVE_WORKSPACE_KEY = 'cbm-active-workspace';

function loadActiveWorkspace() {
  try {
    const saved = localStorage.getItem(ACTIVE_WORKSPACE_KEY);
    if (saved && WORKSPACE_IDS.includes(saved)) return saved;
  } catch {
    /* use default */
  }
  return 'revision';
}

function saveActiveWorkspace(workspace) {
  try {
    localStorage.setItem(ACTIVE_WORKSPACE_KEY, workspace);
  } catch {
    /* ignore */
  }
}

function normalizeLayouts(raw) {
  const next = { ...raw };
  for (const id of WORKSPACE_IDS) {
    if (id === 'time') continue;
    next[id] = validateLayout(next[id] ?? createInitialLayout(id), id);
  }
  return next;
}

export function useLayoutTree() {
  const [activeWorkspace, setActiveWorkspaceState] = useState(loadActiveWorkspace);
  const [layouts, setLayouts] = useState(() => normalizeLayouts(loadWorkspaceLayouts()));
  const [dragState, setDragState] = useState(null);

  const layout = layouts[activeWorkspace] ?? null;

  useEffect(() => {
    saveWorkspaceLayouts(layouts);
  }, [layouts]);

  useEffect(() => {
    saveActiveWorkspace(activeWorkspace);
  }, [activeWorkspace]);

  const visibility = getVisiblePanels(layout, activeWorkspace);

  const setActiveWorkspace = useCallback((workspace) => {
    if (!WORKSPACE_IDS.includes(workspace)) return;
    setActiveWorkspaceState(workspace);
    setLayouts((prev) => {
      if (workspace === 'time' || prev[workspace]) return prev;
      return { ...prev, [workspace]: createInitialLayout(workspace) };
    });
  }, []);

  const updateLayout = useCallback(
    (updater) => {
      setLayouts((prev) => ({
        ...prev,
        [activeWorkspace]: validateLayout(
          updater(prev[activeWorkspace] ?? createInitialLayout(activeWorkspace)),
          activeWorkspace
        ),
      }));
    },
    [activeWorkspace]
  );

  const toggleVisible = useCallback(
    (panelId, visible) => {
      updateLayout((prev) => setPanelVisible(prev, panelId, visible, activeWorkspace));
    },
    [updateLayout, activeWorkspace]
  );

  const resetWindows = useCallback(() => {
    setLayouts((prev) => ({
      ...prev,
      [activeWorkspace]: resetLayout(activeWorkspace),
    }));
  }, [activeWorkspace]);

  const resizeSplit = useCallback(
    (path, ratio) => {
      const clamped = Math.max(MIN_RATIO, Math.min(MAX_RATIO, ratio));
      updateLayout((prev) => updateSplitRatio(prev, path, clamped));
    },
    [updateLayout]
  );

  const startDrag = useCallback((panelId, panelEl) => {
    setDragState({ panelId, panelEl, activeZone: null });
  }, []);

  const updateDragZone = useCallback((zone) => {
    setDragState((prev) => (prev ? { ...prev, activeZone: zone } : null));
  }, []);

  const endDrag = useCallback(() => {
    setDragState((prev) => {
      if (prev?.activeZone) {
        const { panelId, activeZone } = prev;
        if (panelId !== activeZone.targetId) {
          updateLayout((current) =>
            insertAtEdge(current, activeZone.targetId, panelId, activeZone.edge)
          );
        }
      }
      return null;
    });
  }, [updateLayout]);

  return {
    activeWorkspace,
    setActiveWorkspace,
    layout,
    visibility,
    dragState,
    toggleVisible,
    resetWindows,
    resizeSplit,
    startDrag,
    updateDragZone,
    endDrag,
  };
}

export function useSplitResize(direction, onResize) {
  const startResize = useCallback(
    (e) => {
      e.preventDefault();
      const gutter = e.currentTarget;
      const firstPane = gutter.previousElementSibling;
      const secondPane = gutter.nextElementSibling;
      const startPos = direction === 'horizontal' ? e.clientX : e.clientY;
      const totalSize =
        direction === 'horizontal'
          ? firstPane.offsetWidth + secondPane.offsetWidth
          : firstPane.offsetHeight + secondPane.offsetHeight;
      const startSize =
        direction === 'horizontal' ? firstPane.offsetWidth : firstPane.offsetHeight;
      const startRatio = startSize / totalSize;

      const onMove = (moveE) => {
        const current = direction === 'horizontal' ? moveE.clientX : moveE.clientY;
        const delta = current - startPos;
        onResize(startRatio + delta / totalSize);
      };

      const onUp = () => {
        document.removeEventListener('mousemove', onMove);
        document.removeEventListener('mouseup', onUp);
        document.body.style.cursor = '';
        document.body.style.userSelect = '';
      };

      document.body.style.cursor = direction === 'horizontal' ? 'col-resize' : 'row-resize';
      document.body.style.userSelect = 'none';
      document.addEventListener('mousemove', onMove);
      document.addEventListener('mouseup', onUp);
    },
    [direction, onResize]
  );

  return startResize;
}
