import { useCallback, useRef, useState } from 'react';
import type { NodeAction, NodeConfig } from '../ProcessDiagram/types';
import type { ExecutionDetail, ProcessorNode } from './types';
import { useExecutionDetail } from '../../api/queries/executions';
import { useDiagramLayout } from '../../api/queries/diagrams';
import { ProcessDiagram } from '../ProcessDiagram';
import { DetailPanel } from './DetailPanel';
import { useExecutionOverlay } from './useExecutionOverlay';
import { useIterationState } from './useIterationState';
import styles from './ExecutionDiagram.module.css';

interface ExecutionDiagramProps {
  executionId: string;
  executionDetail?: ExecutionDetail;
  direction?: 'LR' | 'TB';
  knownRouteIds?: Set<string>;
  onNodeAction?: (nodeId: string, action: NodeAction) => void;
  nodeConfigs?: Map<string, NodeConfig>;
  className?: string;
}

function findProcessorInTree(
  nodes: ProcessorNode[] | undefined,
  processorId: string | null,
): ProcessorNode | null {
  if (!nodes || !processorId) return null;
  for (const n of nodes) {
    if (n.processorId === processorId) return n;
    if (n.children) {
      const found = findProcessorInTree(n.children, processorId);
      if (found) return found;
    }
  }
  return null;
}

function findFailedProcessor(nodes: ProcessorNode[]): ProcessorNode | null {
  for (const n of nodes) {
    if (n.status === 'FAILED') return n;
    if (n.children) {
      const found = findFailedProcessor(n.children);
      if (found) return found;
    }
  }
  return null;
}

function statusBadgeClass(status: string): string {
  const s = status?.toUpperCase();
  if (s === 'COMPLETED') return `${styles.statusBadge} ${styles.statusCompleted}`;
  if (s === 'FAILED') return `${styles.statusBadge} ${styles.statusFailed}`;
  if (s === 'RUNNING') return `${styles.statusBadge} ${styles.statusRunning}`;
  return styles.statusBadge;
}

export function ExecutionDiagram({
  executionId,
  executionDetail: externalDetail,
  direction = 'LR',
  knownRouteIds,
  onNodeAction,
  nodeConfigs,
  className,
}: ExecutionDiagramProps) {
  // 1. Fetch execution data (skip if pre-fetched prop provided)
  const detailQuery = useExecutionDetail(externalDetail ? null : executionId);
  const detail = externalDetail ?? detailQuery.data;
  const detailLoading = !externalDetail && detailQuery.isLoading;
  const detailError = !externalDetail && detailQuery.error;

  // 2. Load diagram by content hash
  const diagramQuery = useDiagramLayout(detail?.diagramContentHash ?? null, direction);
  const diagramLayout = diagramQuery.data;
  const diagramLoading = diagramQuery.isLoading;
  const diagramError = diagramQuery.error;

  // 3. Initialize iteration state
  const { iterationState, setIteration } = useIterationState(detail?.processors);

  // 4. Compute overlay
  const overlay = useExecutionOverlay(detail?.processors, iterationState);

  // 5. Manage selection
  const [selectedProcessorId, setSelectedProcessorId] = useState<string>('');

  // 6. Resizable splitter state
  const [splitPercent, setSplitPercent] = useState(60);
  const containerRef = useRef<HTMLDivElement>(null);

  const handleSplitterDown = useCallback((e: React.PointerEvent) => {
    e.currentTarget.setPointerCapture(e.pointerId);
    const container = containerRef.current;
    if (!container) return;
    const onMove = (me: PointerEvent) => {
      const rect = container.getBoundingClientRect();
      const y = me.clientY - rect.top;
      const pct = Math.min(85, Math.max(30, (y / rect.height) * 100));
      setSplitPercent(pct);
    };
    const onUp = () => {
      document.removeEventListener('pointermove', onMove);
      document.removeEventListener('pointerup', onUp);
    };
    document.addEventListener('pointermove', onMove);
    document.addEventListener('pointerup', onUp);
  }, []);

  // Jump to error: find first FAILED processor and select it
  const handleJumpToError = useCallback(() => {
    if (!detail?.processors) return;
    const failed = findFailedProcessor(detail.processors);
    if (failed?.processorId) {
      setSelectedProcessorId(failed.processorId);
    }
  }, [detail?.processors]);

  // Loading state
  if (detailLoading || (detail && diagramLoading)) {
    return (
      <div className={`${styles.executionDiagram} ${className ?? ''}`}>
        <div className={styles.loadingState}>Loading execution data...</div>
      </div>
    );
  }

  // Error state
  if (detailError) {
    return (
      <div className={`${styles.executionDiagram} ${className ?? ''}`}>
        <div className={styles.errorState}>Failed to load execution detail</div>
      </div>
    );
  }

  if (diagramError) {
    return (
      <div className={`${styles.executionDiagram} ${className ?? ''}`}>
        <div className={styles.errorState}>Failed to load diagram</div>
      </div>
    );
  }

  if (!detail) {
    return (
      <div className={`${styles.executionDiagram} ${className ?? ''}`}>
        <div className={styles.loadingState}>No execution data</div>
      </div>
    );
  }

  return (
    <div ref={containerRef} className={`${styles.executionDiagram} ${className ?? ''}`}>
      {/* Exchange summary bar */}
      <div className={styles.exchangeBar}>
        <span className={styles.exchangeLabel}>Exchange</span>
        <code className={styles.exchangeId}>{detail.exchangeId || detail.executionId}</code>
        <span className={statusBadgeClass(detail.status)}>
          {detail.status}
        </span>
        <span className={styles.exchangeMeta}>
          {detail.applicationName} / {detail.routeId}
        </span>
        <span className={styles.exchangeMeta}>{detail.durationMs}ms</span>
        {detail.status === 'FAILED' && (
          <button
            className={styles.jumpToError}
            onClick={handleJumpToError}
            type="button"
          >
            Jump to Error
          </button>
        )}
      </div>

      {/* Diagram area */}
      <div className={styles.diagramArea} style={{ height: `${splitPercent}%` }}>
        <ProcessDiagram
          application={detail.applicationName}
          routeId={detail.routeId}
          direction={direction}
          diagramLayout={diagramLayout}
          selectedNodeId={selectedProcessorId}
          onNodeSelect={setSelectedProcessorId}
          onNodeAction={onNodeAction}
          nodeConfigs={nodeConfigs}
          knownRouteIds={knownRouteIds}
          executionOverlay={overlay}
          iterationState={iterationState}
          onIterationChange={setIteration}
        />
      </div>

      {/* Resizable splitter */}
      <div
        className={styles.splitter}
        onPointerDown={handleSplitterDown}
      />

      {/* Detail panel */}
      <div className={styles.detailArea} style={{ height: `${100 - splitPercent}%` }}>
        <DetailPanel
          selectedProcessor={findProcessorInTree(detail.processors, selectedProcessorId || null)}
          executionDetail={detail}
          executionId={executionId}
          onSelectProcessor={setSelectedProcessorId}
        />
      </div>
    </div>
  );
}
