import { useCallback, useRef } from 'react';
import { ResizablePanel, ResizablePanelGroup, ResizableHandle } from '../ui/resizable';
import type { LayoutNode, AppRegistry, PanelComponents } from './types';
import { countPanels } from './layout-utils';
import { PanelSlot } from './PanelSlot';

type WorkspaceRendererProps = {
  layout: LayoutNode;
  registry: AppRegistry;
  components?: PanelComponents;
  interactive?: boolean;
  onSetApp: (panelId: string, appType: string | null) => void;
  onSplit: (panelId: string, direction: 'horizontal' | 'vertical') => void;
  onRemove: (panelId: string) => void;
  onResized: (groupId: string, sizes: number[]) => void;
};

export const WorkspaceRenderer = ({
  layout,
  registry,
  components,
  interactive = false,
  onSetApp,
  onSplit,
  onRemove,
  onResized,
}: WorkspaceRendererProps) => {
  const totalPanels = countPanels(layout);

  return (
    <div className="h-full w-full">
      <LayoutNodeRenderer
        node={layout}
        registry={registry}
        components={components}
        interactive={interactive}
        totalPanels={totalPanels}
        onSetApp={onSetApp}
        onSplit={onSplit}
        onRemove={onRemove}
        onResized={onResized}
      />
    </div>
  );
};

type LayoutNodeRendererProps = {
  node: LayoutNode;
  registry: AppRegistry;
  components?: PanelComponents;
  interactive: boolean;
  totalPanels: number;
  onSetApp: (panelId: string, appType: string | null) => void;
  onSplit: (panelId: string, direction: 'horizontal' | 'vertical') => void;
  onRemove: (panelId: string) => void;
  onResized: (groupId: string, sizes: number[]) => void;
};

const getFixedHeight = (node: LayoutNode, registry: AppRegistry): number | undefined => {
  if (node.type === 'panel' && node.appType) return registry[node.appType]?.fixedHeight;
  return undefined;
};

const LayoutNodeRenderer = ({
  node,
  registry,
  components,
  interactive,
  totalPanels,
  onSetApp,
  onSplit,
  onRemove,
  onResized,
}: LayoutNodeRendererProps) => {
  const debounceRef = useRef<ReturnType<typeof setTimeout>>(null);
  const mountedRef = useRef(false);

  const handleLayout = useCallback(
    (sizes: number[]) => {
      if (node.type !== 'group') return;
      if (!mountedRef.current) {
        mountedRef.current = true;
        return;
      }
      if (debounceRef.current) clearTimeout(debounceRef.current);
      debounceRef.current = setTimeout(() => {
        onResized(node.id, sizes);
      }, 500);
    },
    [node, onResized],
  );

  if (node.type === 'panel') {
    return (
      <PanelSlot
        panel={node}
        registry={registry}
        components={components}
        interactive={interactive}
        isLastPanel={totalPanels <= 1}
        onSetApp={onSetApp}
        onSplit={onSplit}
        onRemove={onRemove}
      />
    );
  }

  const hasFixedChild = node.direction === 'vertical' && node.children.some((c) => getFixedHeight(c.node, registry) !== undefined);

  if (hasFixedChild) {
    return (
      <div className="flex h-full w-full flex-col">
        {node.children.map((child) => {
          const fixed = getFixedHeight(child.node, registry);
          return (
            <div key={child.node.id} className={fixed !== undefined ? 'shrink-0' : 'min-h-0 flex-1'} style={fixed !== undefined ? { height: fixed } : undefined}>
              <LayoutNodeRenderer
                node={child.node}
                registry={registry}
                components={components}
                interactive={interactive}
                totalPanels={totalPanels}
                onSetApp={onSetApp}
                onSplit={onSplit}
                onRemove={onRemove}
                onResized={onResized}
              />
            </div>
          );
        })}
      </div>
    );
  }

  return (
    <ResizablePanelGroup id={node.id} direction={node.direction} onLayout={handleLayout} className="h-full w-full">
      {node.children.map((child, i) => (
        <ChildEntry key={child.node.id} index={i} total={node.children.length}>
          <ResizablePanel id={child.node.id} order={i} defaultSize={child.size} minSize={5}>
            <div className="h-full w-full">
              <LayoutNodeRenderer
                node={child.node}
                registry={registry}
                components={components}
                interactive={interactive}
                totalPanels={totalPanels}
                onSetApp={onSetApp}
                onSplit={onSplit}
                onRemove={onRemove}
                onResized={onResized}
              />
            </div>
          </ResizablePanel>
        </ChildEntry>
      ))}
    </ResizablePanelGroup>
  );
};

type ChildEntryProps = {
  index: number;
  total: number;
  children: React.ReactNode;
};

const ChildEntry = ({ index, total, children }: ChildEntryProps) => {
  if (index === 0) return <>{children}</>;
  return (
    <>
      <ResizableHandle className="bg-transparent after:bg-transparent" />
      {children}
    </>
  );
};
