import { useCallback, useMemo } from "react";
import { useLocalStorage } from "./useLocalStorage";

export interface PanelState {
  id: string;
  /** Flex value for vertical sizing (1 = equal share, 2 = double share, etc.) */
  flex: number;
  collapsed: boolean;
  position: "left" | "right";
  order: number;
}

export interface SidebarWidths {
  left: number;
  right: number;
}

export interface PanelLayoutConfig {
  panels: PanelState[];
  sidebarWidths: SidebarWidths;
  version: number;
}

const STORAGE_KEY = "apollinare-report-editor-panels";
const CONFIG_VERSION = 3; // Bumped version for sidebar widths

// Default sidebar widths
const defaultSidebarWidths: SidebarWidths = {
  left: 250,
  right: 300,
};

// Default panel configuration
const defaultConfig: PanelLayoutConfig = {
  version: CONFIG_VERSION,
  sidebarWidths: defaultSidebarWidths,
  panels: [
    {
      id: "pages",
      flex: 1,
      collapsed: false,
      position: "left",
      order: 0,
    },
    {
      id: "data",
      flex: 1,
      collapsed: false,
      position: "right",
      order: 0,
    },
    {
      id: "properties",
      flex: 1,
      collapsed: false,
      position: "right",
      order: 1,
    },
  ],
};

export function usePanelLayout() {
  const [config, setConfig, clearConfig] = useLocalStorage<PanelLayoutConfig>(
    STORAGE_KEY,
    defaultConfig,
  );

  // Ensure config is up to date (handle version migrations)
  const normalizedConfig = useMemo(() => {
    if (!config) {
      return defaultConfig;
    }

    // If version mismatch, migrate or reset
    if (config.version !== CONFIG_VERSION) {
      console.log(
        "[usePanelLayout] Version mismatch, resetting to default config",
      );
      // Clear old config and return default
      clearConfig();
      return defaultConfig;
    }

    // Ensure all panels have flex property
    const migratedPanels = config.panels.map((p) => ({
      ...p,
      flex: p.flex ?? 1,
    }));

    return {
      ...config,
      sidebarWidths: config.sidebarWidths ?? defaultSidebarWidths,
      panels: migratedPanels,
    };
  }, [config, clearConfig]);

  // Get panel state by id
  const getPanelState = useCallback(
    (panelId: string): PanelState | undefined => {
      return normalizedConfig.panels.find((p) => p.id === panelId);
    },
    [normalizedConfig.panels],
  );

  // Update a single panel's state
  const updatePanel = useCallback(
    (panelId: string, updates: Partial<Omit<PanelState, "id">>) => {
      setConfig((prev) => ({
        ...prev,
        panels: prev.panels.map((p) =>
          p.id === panelId ? { ...p, ...updates } : p,
        ),
      }));
    },
    [setConfig],
  );

  // Toggle panel collapse state
  const togglePanelCollapse = useCallback(
    (panelId: string) => {
      setConfig((prev) => ({
        ...prev,
        panels: prev.panels.map((p) =>
          p.id === panelId ? { ...p, collapsed: !p.collapsed } : p,
        ),
      }));
    },
    [setConfig],
  );

  // Update sidebar width
  const setSidebarWidth = useCallback(
    (position: "left" | "right", width: number) => {
      setConfig((prev) => ({
        ...prev,
        sidebarWidths: {
          ...prev.sidebarWidths,
          [position]: Math.max(180, Math.min(500, width)),
        },
      }));
    },
    [setConfig],
  );

  // Update panel flex value
  const setPanelFlex = useCallback(
    (panelId: string, flex: number) => {
      setConfig((prev) => ({
        ...prev,
        panels: prev.panels.map((p) =>
          p.id === panelId ? { ...p, flex: Math.max(0.2, flex) } : p,
        ),
      }));
    },
    [setConfig],
  );

  // Move panel to a different position (left/right sidebar)
  // Auto-redistributes flex values so all panels in the sidebar share space equally
  const movePanelToPosition = useCallback(
    (panelId: string, newPosition: "left" | "right", newOrder?: number) => {
      setConfig((prev) => {
        const movingPanel = prev.panels.find((p) => p.id === panelId);
        if (!movingPanel) return prev;

        const isMovingToNewSidebar = movingPanel.position !== newPosition;

        // Get panels in the target position (excluding the moving panel)
        const panelsInNewPosition = prev.panels.filter(
          (p) => p.position === newPosition && p.id !== panelId,
        );

        // Calculate new order
        const maxOrder =
          panelsInNewPosition.length > 0
            ? Math.max(...panelsInNewPosition.map((p) => p.order)) + 1
            : 0;
        const finalOrder = newOrder ?? maxOrder;

        // All panels get flex: 1 for equal distribution
        const equalFlex = 1;

        // Get panels in the old position (excluding the moving panel) for rebalancing
        const panelsInOldPosition = prev.panels.filter(
          (p) => p.position === movingPanel.position && p.id !== panelId,
        );

        return {
          ...prev,
          panels: prev.panels.map((p) => {
            // The panel being moved
            if (p.id === panelId) {
              return {
                ...p,
                position: newPosition,
                order: finalOrder,
                flex: equalFlex,
              };
            }

            // Panels in the target sidebar: reset to equal flex
            if (p.position === newPosition && isMovingToNewSidebar) {
              return { ...p, flex: equalFlex };
            }

            // Panels in the old sidebar (after panel leaves): reset to equal flex
            if (
              isMovingToNewSidebar &&
              p.position === movingPanel.position &&
              panelsInOldPosition.length > 0
            ) {
              return { ...p, flex: equalFlex };
            }

            // Adjust order for panels in target position if inserting at specific index
            if (p.position === newPosition && newOrder !== undefined) {
              if (p.order >= newOrder) {
                return { ...p, order: p.order + 1 };
              }
            }

            return p;
          }),
        };
      });
    },
    [setConfig],
  );

  // Reorder panels within a sidebar
  const reorderPanels = useCallback(
    (position: "left" | "right", orderedPanelIds: string[]) => {
      setConfig((prev) => ({
        ...prev,
        panels: prev.panels.map((p) => {
          if (p.position !== position) return p;
          const newOrder = orderedPanelIds.indexOf(p.id);
          return newOrder >= 0 ? { ...p, order: newOrder } : p;
        }),
      }));
    },
    [setConfig],
  );

  // Get panels for a specific position, sorted by order
  const getPanelsForPosition = useCallback(
    (position: "left" | "right"): PanelState[] => {
      return normalizedConfig.panels
        .filter((p) => p.position === position)
        .sort((a, b) => a.order - b.order);
    },
    [normalizedConfig.panels],
  );

  // Get sidebar width
  const getSidebarWidth = useCallback(
    (position: "left" | "right"): number => {
      return normalizedConfig.sidebarWidths[position];
    },
    [normalizedConfig.sidebarWidths],
  );

  // Reset to default configuration
  const resetToDefault = useCallback(() => {
    setConfig(defaultConfig);
  }, [setConfig]);

  return {
    config: normalizedConfig,
    getPanelState,
    updatePanel,
    togglePanelCollapse,
    setSidebarWidth,
    getSidebarWidth,
    setPanelFlex,
    movePanelToPosition,
    reorderPanels,
    getPanelsForPosition,
    resetToDefault,
  };
}

export default usePanelLayout;
