import { useState, useMemo, useCallback, useRef, useEffect } from 'react';
import { useNavigate, useLocation, useParams } from 'react-router';
import { useGlobalFilters } from '@cameleer/design-system';
import { useExecutionDetail } from '../../api/queries/executions';
import { useDiagramByRoute } from '../../api/queries/diagrams';
import { useRouteCatalog } from '../../api/queries/catalog';
import type { NodeAction } from '../../components/ProcessDiagram/types';
import { ExchangeHeader } from './ExchangeHeader';
import { ExecutionDiagram } from '../../components/ExecutionDiagram/ExecutionDiagram';
import { ProcessDiagram } from '../../components/ProcessDiagram';
import styles from './ExchangesPage.module.css';

import Dashboard from '../Dashboard/Dashboard';
import type { SelectedExchange } from '../Dashboard/Dashboard';

export default function ExchangesPage() {
  const navigate = useNavigate();
  const location = useLocation();
  const { appId: scopedAppId, routeId: scopedRouteId } = useParams<{ appId?: string; routeId?: string }>();

  // Restore selection from browser history state (enables Back/Forward)
  const stateSelected = (location.state as any)?.selectedExchange as SelectedExchange | undefined;
  const [selected, setSelectedInternal] = useState<SelectedExchange | null>(stateSelected ?? null);

  // Sync from history state when the user navigates Back/Forward
  useEffect(() => {
    const restored = (location.state as any)?.selectedExchange as SelectedExchange | undefined;
    setSelectedInternal(restored ?? null);
  }, [location.state]);

  const [splitPercent, setSplitPercent] = useState(50);
  const containerRef = useRef<HTMLDivElement>(null);

  // Select an exchange: push a history entry so Back restores the previous state
  const handleExchangeSelect = useCallback((exchange: SelectedExchange) => {
    setSelectedInternal(exchange);
    navigate(location.pathname + location.search, {
      state: { ...location.state, selectedExchange: exchange },
    });
  }, [navigate, location.pathname, location.search, location.state]);

  // Select a correlated exchange: push another history entry
  const handleCorrelatedSelect = useCallback((executionId: string, applicationName: string, routeId: string) => {
    const exchange = { executionId, applicationName, routeId };
    setSelectedInternal(exchange);
    navigate(location.pathname + location.search, {
      state: { ...location.state, selectedExchange: exchange },
    });
  }, [navigate, location.pathname, location.search, location.state]);

  // Clear selection: push a history entry without selection (so Back returns to selected state)
  const handleClearSelection = useCallback(() => {
    setSelectedInternal(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 x = me.clientX - rect.left;
      const pct = Math.min(80, Math.max(20, (x / rect.width) * 100));
      setSplitPercent(pct);
    };
    const onUp = () => {
      document.removeEventListener('pointermove', onMove);
      document.removeEventListener('pointerup', onUp);
    };
    document.addEventListener('pointermove', onMove);
    document.addEventListener('pointerup', onUp);
  }, []);

  // Show split view when a route is scoped (sidebar) or an exchange is selected
  const showSplit = !!selected || !!scopedRouteId;

  if (!showSplit) {
    return <Dashboard onExchangeSelect={handleExchangeSelect} />;
  }

  // Determine what the right panel shows
  const panelAppId = selected?.applicationName ?? scopedAppId!;
  const panelRouteId = selected?.routeId ?? scopedRouteId!;
  const panelExchangeId = selected?.executionId ?? undefined;

  return (
    <div ref={containerRef} className={styles.splitView}>
      <div className={styles.leftPanel} style={{ width: `${splitPercent}%` }}>
        <Dashboard onExchangeSelect={handleExchangeSelect} />
      </div>
      <div className={styles.splitter} onPointerDown={handleSplitterDown} />
      <div className={styles.rightPanel} style={{ width: `${100 - splitPercent}%` }}>
        <DiagramPanel
          appId={panelAppId}
          routeId={panelRouteId}
          exchangeId={panelExchangeId}
          onCorrelatedSelect={handleCorrelatedSelect}
          onClearSelection={handleClearSelection}
        />
      </div>
    </div>
  );
}

// ─── Right panel: diagram + execution overlay ───────────────────────────────

interface DiagramPanelProps {
  appId: string;
  routeId: string;
  exchangeId?: string;
  onCorrelatedSelect: (executionId: string, applicationName: string, routeId: string) => void;
  onClearSelection: () => void;
}

function DiagramPanel({ appId, routeId, exchangeId, onCorrelatedSelect, onClearSelection }: DiagramPanelProps) {
  const navigate = useNavigate();
  const { timeRange } = useGlobalFilters();
  const timeFrom = timeRange.start.toISOString();
  const timeTo = timeRange.end.toISOString();

  const { data: detail } = useExecutionDetail(exchangeId ?? null);
  const diagramQuery = useDiagramByRoute(appId, routeId);

  const { data: catalog } = useRouteCatalog(timeFrom, timeTo);
  const knownRouteIds = useMemo(() => {
    const ids = new Set<string>();
    if (catalog) {
      for (const app of catalog as any[]) {
        for (const r of app.routes || []) {
          ids.add(r.routeId);
        }
      }
    }
    return ids;
  }, [catalog]);

  const handleNodeAction = useCallback((nodeId: string, action: NodeAction) => {
    if (action === 'configure-tap') {
      navigate(`/admin/appconfig?app=${encodeURIComponent(appId)}&processor=${encodeURIComponent(nodeId)}`);
    }
  }, [appId, navigate]);

  // Exchange selected: show header + execution diagram
  if (exchangeId && detail) {
    return (
      <>
        <ExchangeHeader detail={detail} onCorrelatedSelect={onCorrelatedSelect} onClearSelection={onClearSelection} />
        <ExecutionDiagram
          executionId={exchangeId}
          executionDetail={detail}
          knownRouteIds={knownRouteIds}
          onNodeAction={handleNodeAction}
        />
      </>
    );
  }

  // No exchange selected: show topology-only diagram
  if (diagramQuery.data) {
    return (
      <ProcessDiagram
        application={appId}
        routeId={routeId}
        diagramLayout={diagramQuery.data}
        knownRouteIds={knownRouteIds}
        onNodeAction={handleNodeAction}
      />
    );
  }

  return (
    <div className={styles.emptyRight}>
      Loading diagram...
    </div>
  );
}
