// Copyright (c) 2026 PowerOn AG
// All rights reserved.
/**
 * PanelLayout — config-driven horizontal/vertical split layout (MVP).
 *
 * Supports 2+ resizable panes with optional collapse and localStorage persistence.
 * Nested split trees can be composed by nesting PanelLayout instances in pane content.
 */

import {
  useCallback,
  useEffect,
  useMemo,
  useRef,
  useState,
  type CSSProperties,
  type FC,
  type MouseEvent as ReactMouseEvent,
} from 'react';
import { FaChevronLeft, FaChevronRight, FaChevronUp, FaChevronDown } from 'react-icons/fa';
import type { PanelLayoutPaneConfig, PanelLayoutProps } from './types';
import { useVisibilityRemeasure } from '../../hooks/useVisibilityRemeasure';
import { useLanguage } from '../../providers/language/LanguageContext';
import styles from './PanelLayout.module.css';

const STORAGE_PREFIX = 'po_panel_layout:';

function _loadCollapsed(key: string | undefined, fallback: boolean): boolean {
  if (!key) return fallback;
  try {
    const stored = localStorage.getItem(`panel-collapse:${key}`);
    if (stored !== null) return stored === '1';
  } catch { /* noop */ }
  return fallback;
}

function _saveCollapsed(key: string | undefined, value: boolean): void {
  if (!key) return;
  try {
    localStorage.setItem(`panel-collapse:${key}`, value ? '1' : '0');
  } catch { /* noop */ }
}

function _normalizeSizes(sizes: number[]): number[] {
  const total = sizes.reduce((sum, s) => sum + s, 0);
  if (total <= 0) return sizes.map(() => 100 / sizes.length);
  return sizes.map((s) => (s / total) * 100);
}

function _loadSizes(persistenceKey: string, panes: PanelLayoutPaneConfig[]): number[] {
  const defaults = panes.map((p) => p.defaultSize ?? 100 / panes.length);
  try {
    const raw = localStorage.getItem(`${STORAGE_PREFIX}${persistenceKey}`);
    if (!raw) return _normalizeSizes(defaults);
    const parsed = JSON.parse(raw) as number[];
    if (!Array.isArray(parsed) || parsed.length !== panes.length) {
      return _normalizeSizes(defaults);
    }
    return _normalizeSizes(parsed);
  } catch {
    return _normalizeSizes(defaults);
  }
}

function _saveSizes(persistenceKey: string, sizes: number[]): void {
  try {
    localStorage.setItem(`${STORAGE_PREFIX}${persistenceKey}`, JSON.stringify(sizes));
  } catch { /* noop */ }
}

function _clampPaneSize(
  pane: PanelLayoutPaneConfig,
  size: number,
): number {
  const min = pane.minSize ?? 10;
  const max = pane.maxSize ?? 80;
  return Math.max(min, Math.min(max, size));
}

export const PanelLayout: FC<PanelLayoutProps> = ({
  persistenceKey,
  direction = 'horizontal',
  panes,
  className = '',
}) => {
  const { t } = useLanguage();
  const containerRef = useRef<HTMLDivElement>(null);
  const [sizes, setSizes] = useState<number[]>(() => _loadSizes(persistenceKey, panes));
  const [collapsedById, setCollapsedById] = useState<Record<string, boolean>>(() => {
    const initial: Record<string, boolean> = {};
    for (const pane of panes) {
      initial[pane.id] = _loadCollapsed(pane.collapseKey, pane.defaultCollapsed ?? false);
    }
    return initial;
  });
  const [draggingIndex, setDraggingIndex] = useState<number | null>(null);
  const dragRef = useRef<{ index: number; startPos: number; startSizes: number[]; containerSize: number } | null>(null);

  useEffect(() => {
    setSizes(_loadSizes(persistenceKey, panes));
  }, [persistenceKey, panes.length]);

  useEffect(() => {
    if (draggingIndex === null) {
      _saveSizes(persistenceKey, sizes);
    }
  }, [sizes, persistenceKey, draggingIndex]);

  const _toggleCollapsed = useCallback((pane: PanelLayoutPaneConfig) => {
    setCollapsedById((prev) => {
      const next = !prev[pane.id];
      _saveCollapsed(pane.collapseKey, next);
      return { ...prev, [pane.id]: next };
    });
  }, []);

  const _handleDividerMouseDown = useCallback((index: number, e: ReactMouseEvent) => {
    e.preventDefault();
    const container = containerRef.current;
    if (!container) return;

    const rect = container.getBoundingClientRect();
    const containerSize = direction === 'horizontal' ? rect.width : rect.height;
    const startPos = direction === 'horizontal' ? e.clientX : e.clientY;

    dragRef.current = { index, startPos, startSizes: [...sizes], containerSize };
    setDraggingIndex(index);
  }, [direction, sizes]);

  useEffect(() => {
    if (draggingIndex === null) return;

    const _onMouseMove = (e: MouseEvent) => {
      const drag = dragRef.current;
      if (!drag) return;

      const currentPos = direction === 'horizontal' ? e.clientX : e.clientY;
      const deltaPercent = ((currentPos - drag.startPos) / drag.containerSize) * 100;
      const next = [...drag.startSizes];
      const leftPane = panes[drag.index];
      const rightPane = panes[drag.index + 1];

      let leftSize = next[drag.index] + deltaPercent;
      let rightSize = next[drag.index + 1] - deltaPercent;

      leftSize = _clampPaneSize(leftPane, leftSize);
      rightSize = _clampPaneSize(rightPane, rightSize);

      const pairTotal = drag.startSizes[drag.index] + drag.startSizes[drag.index + 1];
      const adjustedTotal = leftSize + rightSize;
      if (Math.abs(adjustedTotal - pairTotal) > 0.01) {
        const scale = pairTotal / adjustedTotal;
        leftSize *= scale;
        rightSize *= scale;
      }

      next[drag.index] = leftSize;
      next[drag.index + 1] = rightSize;
      setSizes(_normalizeSizes(next));
    };

    const _onMouseUp = () => {
      dragRef.current = null;
      setDraggingIndex(null);
      document.body.style.cursor = '';
      document.body.style.userSelect = '';
    };

    document.addEventListener('mousemove', _onMouseMove);
    document.addEventListener('mouseup', _onMouseUp);
    document.body.style.cursor = direction === 'horizontal' ? 'col-resize' : 'row-resize';
    document.body.style.userSelect = 'none';

    return () => {
      document.removeEventListener('mousemove', _onMouseMove);
      document.removeEventListener('mouseup', _onMouseUp);
      document.body.style.cursor = '';
      document.body.style.userSelect = '';
    };
  }, [draggingIndex, direction, panes]);

  const _remeasure = useCallback(() => {
    containerRef.current?.dispatchEvent(new Event('panel-layout-remeasure'));
  }, []);

  useVisibilityRemeasure(containerRef, _remeasure);

  const paneStyle = useCallback((pane: PanelLayoutPaneConfig, index: number): CSSProperties => {
    const collapsed = collapsedById[pane.id] && pane.collapsible;
    if (collapsed) {
      const collapsedPx = pane.collapsedSize ?? 40;
      return direction === 'horizontal'
        ? { flex: `0 0 ${collapsedPx}px`, width: collapsedPx }
        : { flex: `0 0 ${collapsedPx}px`, height: collapsedPx };
    }
    const percent = sizes[index] ?? 100 / panes.length;
    return { flex: `${percent} 1 0`, minWidth: 0, minHeight: 0 };
  }, [collapsedById, direction, panes.length, sizes]);

  const dividerClass = useMemo(
    () => `${styles.divider} ${direction === 'horizontal' ? styles.dividerHorizontal : styles.dividerVertical}`,
    [direction],
  );

  if (panes.length < 2) {
    throw new Error('PanelLayout requires at least 2 panes');
  }

  return (
    <div
      ref={containerRef}
      className={`${styles.root} ${className}`}
      data-direction={direction}
      role="group"
    >
      {panes.map((pane, index) => (
        <PaneSlot
          key={pane.id}
          pane={pane}
          style={paneStyle(pane, index)}
          collapsed={!!collapsedById[pane.id] && !!pane.collapsible}
          onToggleCollapse={() => _toggleCollapsed(pane)}
          collapseLabel={t('Panel einklappen')}
          expandLabel={t('Panel ausklappen')}
          direction={direction}
          showDivider={index < panes.length - 1}
          dividerClass={`${dividerClass} ${draggingIndex === index ? styles.dividerDragging : ''}`}
          onDividerMouseDown={(e) => _handleDividerMouseDown(index, e)}
        />
      ))}
    </div>
  );
};

interface PaneSlotProps {
  pane: PanelLayoutPaneConfig;
  style: CSSProperties;
  collapsed: boolean;
  onToggleCollapse: () => void;
  collapseLabel: string;
  expandLabel: string;
  direction: 'horizontal' | 'vertical';
  showDivider: boolean;
  dividerClass: string;
  onDividerMouseDown: (e: ReactMouseEvent) => void;
}

const PaneSlot: FC<PaneSlotProps> = ({
  pane,
  style,
  collapsed,
  onToggleCollapse,
  collapseLabel,
  expandLabel,
  direction,
  showDivider,
  dividerClass,
  onDividerMouseDown,
}) => {
  const _collapseIcon = direction === 'horizontal'
    ? (collapsed ? <FaChevronRight aria-hidden /> : <FaChevronLeft aria-hidden />)
    : (collapsed ? <FaChevronDown aria-hidden /> : <FaChevronUp aria-hidden />);

  return (
  <>
    <div
      className={`${styles.pane} ${collapsed ? styles.paneCollapsed : ''}`}
      style={style}
      data-pane-id={pane.id}
    >
      {pane.collapsible && (
        <button
          type="button"
          className={styles.collapseToggle}
          onClick={onToggleCollapse}
          aria-expanded={!collapsed}
          aria-label={collapsed ? expandLabel : collapseLabel}
        >
          {_collapseIcon}
        </button>
      )}
      <div className={`${styles.paneBody} ${collapsed ? styles.paneBodyHidden : ''}`}>
        {pane.content}
      </div>
    </div>
    {showDivider && (
      <div
        className={dividerClass}
        role="separator"
        aria-orientation="vertical"
        onMouseDown={onDividerMouseDown}
      />
    )}
  </>
  );
};

export default PanelLayout;
