import React, { useEffect, useMemo, useRef, useState } from 'react';
import { createRoot } from 'react-dom/client';
import { SCENARIOS } from './fixtures.js';
import {
  ScenarioMap, OrdersPanel, AgentFeed, RewardPanel,
  ControlBar, TickScrubber, FinalCard, ActionBanner,
} from './components.jsx';
import './styles.css';

const MODES = [
  { id: 'trained', label: 'AI agent (trained LoRA)', shortLabel: 'Trained policy', tone: 'trained' },
  { id: 'heuristic', label: 'Heuristic dispatcher', shortLabel: 'Heuristic baseline', tone: 'heuristic' },
  { id: 'prompt_only', label: 'Prompt-only agent', shortLabel: 'Untrained baseline', tone: 'baseline' },
];

const THINKING_MS = 1800;
const ACTION_MS = 1200;

function getTrajectory(scenario, modeId) {
  return scenario.trajectories[modeId] || scenario.trajectories.trained;
}

function summarizeScenario(scenario, modeId) {
  const trajectory = getTrajectory(scenario, modeId);
  const first = trajectory[0];
  const last = trajectory[trajectory.length - 1];
  const delivered = last.orders.filter((o) => o.status === 'delivered').length;
  const expired = last.orders.filter((o) => o.status === 'expired').length;
  const onTime = last.orders.filter(
    (o) => o.status === 'delivered' && (o.delivered_tick ?? 999) <= o.deadline_tick,
  ).length;
  const successRate = last.orders.length ? (delivered / last.orders.length) * 100 : 0;
  return {
    trajectory,
    previewTick: Math.min(2, trajectory.length - 1),
    delivered,
    expired,
    onTime,
    successRate,
    totalReward: last.cumulative_reward ?? 0,
    activeOrdersAtStart: first.orders.length,
    couriersAtStart: first.couriers.length,
    maxTicks: scenario.metadata.max_ticks,
  };
}

function ScenarioSummary({ scenario }) {
  const m = scenario.metadata;
  return (
    <div className="scenario-summary">
      <div className="scenario-row">
        <span className={`difficulty-badge ${m.difficulty}`}>{m.difficulty}</span>
        <span className="scenario-meta">{m.num_couriers} couriers · {m.num_orders} orders · {m.max_ticks} ticks</span>
      </div>
      <div className="scenario-skills">
        {m.skill_focus.map((s) => <span key={s} className="skill-tag">{s.replace(/_/g, ' ')}</span>)}
      </div>
      <div className="scenario-desc">{m.description}</div>
    </div>
  );
}

function PlaybackPanel({ scenario, modeId, currentTick, onJumpToTick, showRewards }) {
  const trajectory = getTrajectory(scenario, modeId);
  const snapshot = trajectory[Math.min(currentTick, trajectory.length - 1)];
  const isFinished = currentTick >= trajectory.length - 1;

  return (
    <div className="playback-col">
      <div className="map-area">
        <ScenarioMap nodes={scenario.nodes} snapshot={snapshot} />
        {isFinished && <div className="map-final-overlay"><FinalCard trajectory={trajectory} scenario={scenario} /></div>}
      </div>
      <OrdersPanel snapshot={snapshot} maxTicks={scenario.metadata.max_ticks} />
      <RewardPanel
        snapshot={snapshot}
        cumulative={snapshot.cumulative_reward ?? 0}
        showRewards={showRewards}
      />
      <AgentFeed trajectory={trajectory} currentTick={currentTick} onJumpToTick={onJumpToTick} />
    </div>
  );
}

function OverviewSidebar({
  scenarios,
  scenarioId,
  onScenarioChange,
  modeId,
  onModeChange,
  onOpenPlayground,
  onAutoplayDemo,
}) {
  return (
    <aside className="overview-sidebar">
      <div className="overview-sidebar-brand">
        <div className="overview-brand-title">Dispatch Control Room</div>
        <div className="overview-brand-subtitle">delivery intelligence unit</div>
      </div>

      <div className="overview-sidebar-section">
        <div className="overview-label">Simulation difficulty</div>
        <select className="overview-select" value={scenarioId} onChange={(e) => onScenarioChange(e.target.value)}>
          {Object.entries(scenarios).map(([id, s]) => (
            <option key={id} value={id}>
              {s.metadata.theme}
            </option>
          ))}
        </select>
      </div>

      <div className="overview-sidebar-section">
        <div className="overview-label">Active intelligence</div>
        <div className="mode-stack">
          {MODES.map((mode) => (
            <button
              key={mode.id}
              className={`mode-card ${modeId === mode.id ? 'selected' : ''}`}
              onClick={() => onModeChange(mode.id)}
            >
              <span className={`mode-dot ${mode.tone}`} />
              <span>{mode.shortLabel}</span>
            </button>
          ))}
        </div>
      </div>

      <div className="overview-actions">
        <button className="launch-btn primary" onClick={() => onOpenPlayground(false)}>Run playground</button>
        <button className="launch-btn" onClick={onAutoplayDemo}>Autoplay demo</button>
      </div>

      <div className="overview-note">
        Choose a scenario, pick the policy to inspect, and jump into the replay playground for step-by-step dispatch simulation.
      </div>
    </aside>
  );
}

function HeroPanel({ scenario, modeId }) {
  const mode = MODES.find((item) => item.id === modeId) || MODES[0];
  return (
    <section className="hero-panel">
      <div className="hero-badge">dispatch arena // live replay interface</div>
      <h1>Dispatch intelligence for food and grocery delivery</h1>
      <p>
        Explore how different dispatch policies behave under hidden prep times, deadline pressure,
        rolling arrivals, and traffic noise. The environment is packaged for OpenEnv, GRPO training,
        and public interactive demos on Hugging Face Spaces.
      </p>
      <div className="hero-pills">
        <span className={`hero-pill ${scenario.metadata.difficulty}`}>{scenario.metadata.difficulty}</span>
        <span className="hero-pill neutral">{scenario.metadata.theme}</span>
        <span className="hero-pill accent">{mode.shortLabel}</span>
      </div>
    </section>
  );
}

function MetricCard({ title, eyebrow, children, tall = false }) {
  return (
    <section className={`overview-card${tall ? ' tall' : ''}`}>
      <div className="overview-card-title">{title}</div>
      <div className="overview-card-eyebrow">{eyebrow}</div>
      <div className="overview-card-body">{children}</div>
    </section>
  );
}

function MetricBar({ label, value, max = 100, tone = 'accent' }) {
  const width = Math.max(6, Math.min(100, (value / max) * 100));
  return (
    <div className="metric-bar-row">
      <div className="metric-bar-header">
        <span>{label}</span>
        <span>{typeof value === 'number' ? value.toFixed(0) : value}</span>
      </div>
      <div className="metric-bar-track">
        <div className={`metric-bar-fill ${tone}`} style={{ width: `${width}%` }} />
      </div>
    </div>
  );
}

function OverviewPage({ scenario, modeId, onOpenPlayground }) {
  const summary = summarizeScenario(scenario, modeId);
  const previewSnapshot = summary.trajectory[summary.previewTick];

  return (
    <main className="overview-main">
      <HeroPanel scenario={scenario} modeId={modeId} />

      <div className="overview-grid">
        <MetricCard title="Live Shift State" eyebrow="replay preview of the selected scenario" tall>
          <div className="overview-map-frame">
            <ScenarioMap nodes={scenario.nodes} snapshot={previewSnapshot} />
          </div>
          <div className="overview-inline-stats">
            <div className="overview-inline-stat">
              <span className="overview-inline-label">Tick preview</span>
              <strong>t{previewSnapshot.tick}</strong>
            </div>
            <div className="overview-inline-stat">
              <span className="overview-inline-label">Orders visible</span>
              <strong>{summary.activeOrdersAtStart}</strong>
            </div>
            <div className="overview-inline-stat">
              <span className="overview-inline-label">Couriers online</span>
              <strong>{summary.couriersAtStart}</strong>
            </div>
          </div>
        </MetricCard>

        <MetricCard title="Performance Analytics" eyebrow="policy-level replay outcome">
          <MetricBar label="Deliveries completed" value={summary.delivered} max={scenario.metadata.num_orders} tone="good" />
          <MetricBar label="On-time deliveries" value={summary.onTime} max={Math.max(summary.delivered, 1)} tone="accent" />
          <MetricBar label="Success rate" value={summary.successRate} max={100} tone="accent" />
          <MetricBar label="Expired orders" value={summary.expired} max={scenario.metadata.num_orders} tone="bad" />
          <div className="analytics-reward">
            <span>Total replay reward</span>
            <strong>{summary.totalReward >= 0 ? '+' : ''}{summary.totalReward.toFixed(2)}</strong>
          </div>
        </MetricCard>

        <MetricCard title="Dispatch Constraints" eyebrow="what makes the environment hard">
          <ul className="constraint-list">
            <li>Hidden restaurant prep times and delayed readiness.</li>
            <li>Overlapping orders with shared courier capacity.</li>
            <li>Deadline pressure and lateness penalties.</li>
            <li>Traffic-sensitive travel times and route churn cost.</li>
            <li>Fairness pressure across the active courier fleet.</li>
          </ul>
        </MetricCard>

        <MetricCard title="Environment Contract" eyebrow="OpenEnv + replay-friendly surface">
          <div className="endpoint-grid">
            {['/reset', '/step', '/state', '/summary', '/api/sessions', '/ready'].map((endpoint) => (
              <span key={endpoint} className="endpoint-pill">{endpoint}</span>
            ))}
          </div>
          <div className="contract-copy">
            The same environment powers the public frontend, the replay interface, and GRPO training loops through the OpenEnv contract.
          </div>
          <button className="launch-btn primary full" onClick={() => onOpenPlayground(false)}>Open interactive playground</button>
        </MetricCard>
      </div>
    </main>
  );
}

function PlaygroundHeader({ onBack, scenario, modeId }) {
  const mode = MODES.find((item) => item.id === modeId) || MODES[0];
  return (
    <div className="playground-header">
      <button className="back-btn" onClick={onBack}>← Back to overview</button>
      <div className="playground-header-copy">
        <div className="playground-title">Simulation playground</div>
        <div className="playground-subtitle">
          {scenario.metadata.theme} · {mode.shortLabel}
        </div>
      </div>
    </div>
  );
}

function App() {
  const scenarioIds = Object.keys(SCENARIOS);
  const [scenarioId, setScenarioId] = useState(scenarioIds[0]);
  const [modeId, setModeId] = useState('trained');
  const [currentTick, setCurrentTick] = useState(0);
  const [hasReplayInteraction, setHasReplayInteraction] = useState(false);
  const [isPlaying, setIsPlaying] = useState(false);
  const [playbackPhase, setPlaybackPhase] = useState('idle');
  const [view, setView] = useState('overview');

  const scenario = SCENARIOS[scenarioId];
  const trajectory = getTrajectory(scenario, modeId);
  const trajectoryLen = useMemo(() => trajectory.length, [trajectory]);

  useEffect(() => {
    setCurrentTick(0);
    setHasReplayInteraction(false);
    setIsPlaying(false);
    setPlaybackPhase('idle');
  }, [scenarioId, modeId]);

  useEffect(() => {
    if (currentTick > 0) {
      setHasReplayInteraction(true);
    }
  }, [currentTick]);

  const timeoutRef = useRef(null);
  useEffect(() => {
    if (timeoutRef.current) {
      clearTimeout(timeoutRef.current);
      timeoutRef.current = null;
    }

    if (!isPlaying) {
      setPlaybackPhase('idle');
      return;
    }

    if (currentTick >= trajectoryLen - 1) {
      setIsPlaying(false);
      setPlaybackPhase('idle');
      return;
    }

    setPlaybackPhase('thinking');
    timeoutRef.current = setTimeout(() => {
      setPlaybackPhase('acting');
      timeoutRef.current = setTimeout(() => {
        setCurrentTick((prev) => {
          if (prev >= trajectoryLen - 1) {
            setIsPlaying(false);
            return prev;
          }
          return prev + 1;
        });
      }, ACTION_MS);
    }, THINKING_MS);

    return () => {
      if (timeoutRef.current) {
        clearTimeout(timeoutRef.current);
        timeoutRef.current = null;
      }
    };
  }, [isPlaying, currentTick, trajectoryLen]);

  const jumpToTick = (tick) => {
    setIsPlaying(false);
    setPlaybackPhase('idle');
    setHasReplayInteraction(true);
    setCurrentTick(tick);
  };

  const stepBack = () => {
    setIsPlaying(false);
    setPlaybackPhase('idle');
    setHasReplayInteraction(true);
    setCurrentTick((t) => Math.max(0, t - 1));
  };

  const stepForward = () => {
    setIsPlaying(false);
    setPlaybackPhase('idle');
    setHasReplayInteraction(true);
    setCurrentTick((t) => Math.min(trajectoryLen - 1, t + 1));
  };

  const resetPlayback = () => {
    setCurrentTick(0);
    setHasReplayInteraction(true);
    setIsPlaying(false);
    setPlaybackPhase('idle');
  };

  const openPlayground = (autoplay = false) => {
    setView('playground');
    setCurrentTick(0);
    setHasReplayInteraction(false);
    setPlaybackPhase('idle');
    setIsPlaying(autoplay);
  };

  return (
    <div className={`app view-${view}`}>
      {view === 'overview' ? (
        <div className="overview-shell">
          <OverviewSidebar
            scenarios={SCENARIOS}
            scenarioId={scenarioId}
            onScenarioChange={setScenarioId}
            modeId={modeId}
            onModeChange={setModeId}
            onOpenPlayground={openPlayground}
            onAutoplayDemo={() => openPlayground(true)}
          />
          <OverviewPage scenario={scenario} modeId={modeId} onOpenPlayground={openPlayground} />
        </div>
      ) : (
        <>
          <PlaygroundHeader onBack={() => { setView('overview'); setIsPlaying(false); }} scenario={scenario} modeId={modeId} />
          <ControlBar
            scenarios={SCENARIOS}
            scenarioId={scenarioId}
            onScenarioChange={setScenarioId}
            modes={MODES}
            modeId={modeId}
            onModeChange={setModeId}
            isPlaying={isPlaying}
            onPlayToggle={() => setIsPlaying((p) => !p)}
            onStepBack={stepBack}
            onStepForward={stepForward}
            onReset={resetPlayback}
          />

          <ScenarioSummary scenario={scenario} />

          <ActionBanner
            trajectory={trajectory}
            currentTick={currentTick}
            playbackPhase={playbackPhase}
            isPlaying={isPlaying}
          />

          <div className="workspace">
            <PlaybackPanel
              scenario={scenario}
              modeId={modeId}
              currentTick={currentTick}
              onJumpToTick={jumpToTick}
              showRewards={hasReplayInteraction}
            />
          </div>

          <TickScrubber
            trajectory={trajectory}
            currentTick={currentTick}
            onTickChange={jumpToTick}
            maxTicks={scenario.metadata.max_ticks}
          />
        </>
      )}
    </div>
  );
}

createRoot(document.getElementById('root')).render(<App />);
