import { useEffect, useMemo, useState } from 'react';
import { api } from '../../api/client';
import { useModalAmbientDuck } from '../../context/AmbientMusicContext';
import { useWebSocket } from '../../hooks/useWebSocket';
import { useFleetGroups } from '../../hooks/useFleetGroups';
import type { FleetModuleManifest } from '../../types';
import NeonCard from '../NeonCard/NeonCard';
import { HelpTip } from '../HelpTip';
import './FleetRuntimePanel.css';

type TargetMode = 'all' | 'group';
type WizardStep = 1 | 2 | 3 | 4;

const POLICY_STEPS: { step: WizardStep; label: string }[] = [
  { step: 1, label: 'Pick target' },
  { step: 2, label: 'Set policy' },
  { step: 3, label: 'Confirm push' },
  { step: 4, label: 'Live acks' },
];

function stepStatus(current: WizardStep, step: WizardStep): 'done' | 'active' | 'pending' {
  if (step < current) return 'done';
  if (step === current) return 'active';
  return 'pending';
}

export default function FleetRuntimePanel() {
  const { agents, policyAcks } = useWebSocket();
  const { groups } = useFleetGroups();
  const [modules, setModules] = useState<FleetModuleManifest[]>([]);
  const [wizardStep, setWizardStep] = useState<WizardStep>(1);
  const [targetMode, setTargetMode] = useState<TargetMode>('all');
  const [groupId, setGroupId] = useState('');
  const [selectedModule, setSelectedModule] = useState('crucible_ops');
  const [miningMode, setMiningMode] = useState('scheduled');
  const [scheduleStart, setScheduleStart] = useState('22:00');
  const [scheduleEnd, setScheduleEnd] = useState('06:00');
  const [maxCpu, setMaxCpu] = useState(75);
  const [poolHost, setPoolHost] = useState('');
  const [poolPort, setPoolPort] = useState(0);
  const [policyMsg, setPolicyMsg] = useState('');
  const [moduleMsg, setModuleMsg] = useState('');
  const [pushingPolicy, setPushingPolicy] = useState(false);
  const [pushingModule, setPushingModule] = useState(false);
  const [pushId, setPushId] = useState<string | null>(null);
  const [expectedSent, setExpectedSent] = useState(0);
  useModalAmbientDuck(wizardStep === 3);

  useEffect(() => {
    api.listFleetModules().then(setModules).catch(() => setModules([]));
  }, []);

  const onlineCount = useMemo(() => agents.filter((a) => a.status === 'online').length, [agents]);

  const targetLabel = useMemo(() => {
    if (targetMode === 'all') return `All online (${onlineCount})`;
    const g = groups.find((x) => x.id === groupId);
    return g ? `${g.name} (${g.agentIds.length} agents)` : 'No group selected';
  }, [targetMode, groupId, groups, onlineCount]);

  const ackCount = useMemo(() => {
    if (!pushId) return 0;
    const ids = new Set<string>();
    for (const ack of policyAcks) {
      if (ack.push_id === pushId && ack.agent_id) ids.add(ack.agent_id);
    }
    return ids.size;
  }, [policyAcks, pushId]);

  const resolveAgentIds = (): string[] => {
    if (targetMode === 'all') return ['all'];
    const g = groups.find((x) => x.id === groupId);
    if (!g || g.agentIds.length === 0) return [];
    return g.agentIds;
  };

  const targetReady = targetMode === 'all' || (groupId !== '' && resolveAgentIds().length > 0);

  const handlePushPolicy = async () => {
    const agent_ids = resolveAgentIds();
    if (agent_ids.length === 0) {
      setPolicyMsg('Select a group with agents or use All online.');
      return;
    }
    setPushingPolicy(true);
    setPolicyMsg('');
    try {
      const policy: Record<string, unknown> = {
        mining_mode: miningMode,
        max_cpu_usage_pct: maxCpu,
      };
      if (miningMode === 'scheduled') {
        policy.schedule_start = scheduleStart;
        policy.schedule_end = scheduleEnd;
      }
      if (poolHost.trim()) {
        policy.pool_host = poolHost.trim();
        if (poolPort > 0) policy.pool_port = poolPort;
      }
      const res = await api.pushFleetPolicy({ agent_ids, policy });
      if (res.success) {
        setPushId(res.push_id ?? null);
        setExpectedSent(res.sent ?? 0);
        setWizardStep(4);
        setPolicyMsg(
          `Policy dispatched to ${res.sent} agent(s)${res.failed ? ` (${res.failed} delivery failures)` : ''}. Waiting for live acks…`,
        );
      } else {
        setPolicyMsg(res.error || 'No agents received the policy.');
      }
    } catch (e) {
      setPolicyMsg(e instanceof Error ? e.message : 'Push failed');
    } finally {
      setPushingPolicy(false);
    }
  };

  const handlePushModule = async () => {
    const agent_ids = resolveAgentIds();
    if (agent_ids.length === 0) {
      setModuleMsg('Select a group with agents or use All online.');
      return;
    }
    setPushingModule(true);
    setModuleMsg('');
    try {
      const res = await api.pushFleetModule({ agent_ids, module: selectedModule });
      setModuleMsg(
        res.success
          ? `Module "${res.module}" queued for ${res.sent} agent(s).`
          : res.error || 'No agents received the module push.',
      );
    } catch (e) {
      setModuleMsg(e instanceof Error ? e.message : 'Push failed');
    } finally {
      setPushingModule(false);
    }
  };

  const resetWizard = () => {
    setWizardStep(1);
    setPushId(null);
    setExpectedSent(0);
    setPolicyMsg('');
  };

  return (
    <>
      <NeonCard accent="green" className="settings-section fleet-policy-deck operator-deck-card operator-interactive" hud>
        <p className="fleet-policy-eyebrow font-tech">RUNTIME · NO RE-FORGE</p>
        <h2 className="font-display">Live Fleet Policy <HelpTip field="fleet_runtime_policy" /></h2>
        <p className="section-desc">
          Push live mining rules to connected workers — schedule, CPU cap, and optional pool overrides apply in memory
          via <code className="mono-sm">policy_update</code>. Identity and baked forge options stay on the binary; this
          panel never replaces the Forge builder.
        </p>

        <div className="forge-mission-steps fleet-policy-steps" aria-label="Policy push steps">
          {POLICY_STEPS.map(({ step, label }) => {
            const status = stepStatus(wizardStep, step);
            return (
              <span key={step} className={`forge-mission-step ${status}`}>
                {status === 'done' ? '✓' : status === 'active' ? '●' : '○'} {step}. {label}
              </span>
            );
          })}
        </div>

        {wizardStep === 1 && (
          <div className="fleet-policy-step-panel operator-interactive">
            <h3 className="fleet-policy-step-title">Step 1 — Pick target</h3>
            <div className="form-row">
              <div className="form-group">
                <label className="label" htmlFor="fleet-target-mode">
                  Target fleet
                </label>
                <select
                  id="fleet-target-mode"
                  className="input"
                  value={targetMode}
                  onChange={(e) => setTargetMode(e.target.value as TargetMode)}
                >
                  <option value="all">All online ({onlineCount})</option>
                  <option value="group">Fleet group</option>
                </select>
              </div>
              {targetMode === 'group' && (
                <div className="form-group">
                  <label className="label" htmlFor="fleet-group">
                    Group
                  </label>
                  <select
                    id="fleet-group"
                    className="input"
                    value={groupId}
                    onChange={(e) => setGroupId(e.target.value)}
                  >
                    <option value="">Select group…</option>
                    {groups.map((g) => (
                      <option key={g.id} value={g.id}>
                        {g.name} ({g.agentIds.length})
                      </option>
                    ))}
                  </select>
                </div>
              )}
            </div>
            <div className="fleet-policy-step-actions">
              <button
                type="button"
                className="btn btn-primary"
                disabled={!targetReady}
                onClick={() => setWizardStep(2)}
              >
                Next — Set policy
              </button>
            </div>
          </div>
        )}

        {wizardStep === 2 && (
          <div className="fleet-policy-step-panel operator-interactive">
            <h3 className="fleet-policy-step-title">Step 2 — Set policy</h3>
            <p className="form-hint">Target: {targetLabel}</p>
            <div className="form-row">
              <div className="form-group">
                <label className="label" htmlFor="fleet-mining-mode">
                  Mining mode
                </label>
                <select
                  id="fleet-mining-mode"
                  className="input"
                  value={miningMode}
                  onChange={(e) => setMiningMode(e.target.value)}
                >
                  <option value="always">Always</option>
                  <option value="idle">Idle</option>
                  <option value="scheduled">Scheduled</option>
                </select>
              </div>
              <div className="form-group">
                <label className="label" htmlFor="fleet-max-cpu">
                  Max CPU %
                </label>
                <input
                  id="fleet-max-cpu"
                  type="number"
                  className="input"
                  min={10}
                  max={100}
                  value={maxCpu}
                  onChange={(e) => setMaxCpu(parseInt(e.target.value, 10) || 75)}
                />
              </div>
            </div>
            {miningMode === 'scheduled' && (
              <div className="form-row">
                <div className="form-group">
                  <label className="label" htmlFor="fleet-sched-start">
                    Mine from
                  </label>
                  <input
                    id="fleet-sched-start"
                    type="time"
                    className="input"
                    value={scheduleStart}
                    onChange={(e) => setScheduleStart(e.target.value)}
                  />
                </div>
                <div className="form-group">
                  <label className="label" htmlFor="fleet-sched-end">
                    Mine until
                  </label>
                  <input
                    id="fleet-sched-end"
                    type="time"
                    className="input"
                    value={scheduleEnd}
                    onChange={(e) => setScheduleEnd(e.target.value)}
                  />
                </div>
              </div>
            )}
            <div className="form-row">
              <div className="form-group">
                <label className="label" htmlFor="fleet-pool-host">
                  Pool host (optional)
                </label>
                <input
                  id="fleet-pool-host"
                  type="text"
                  className="input mono"
                  placeholder="leave blank to keep baked pool"
                  value={poolHost}
                  onChange={(e) => setPoolHost(e.target.value)}
                />
              </div>
              <div className="form-group">
                <label className="label" htmlFor="fleet-pool-port">
                  Pool port
                </label>
                <input
                  id="fleet-pool-port"
                  type="number"
                  className="input"
                  min={0}
                  value={poolPort || ''}
                  onChange={(e) => setPoolPort(parseInt(e.target.value, 10) || 0)}
                />
              </div>
            </div>
            <div className="fleet-policy-step-actions">
              <button type="button" className="btn btn-outline" onClick={() => setWizardStep(1)}>
                Back
              </button>
              <button type="button" className="btn btn-primary" onClick={() => setWizardStep(3)}>
                Next — Review
              </button>
            </div>
          </div>
        )}

        {wizardStep === 3 && (
          <div className="fleet-policy-step-panel operator-interactive">
            <h3 className="fleet-policy-step-title">Step 3 — Confirm push</h3>
            <div className="fleet-policy-review">
              <p>
                <strong>Target:</strong> {targetLabel}
              </p>
              <p>
                <strong>Mining:</strong> {miningMode}
                {miningMode === 'scheduled' ? ` · ${scheduleStart} → ${scheduleEnd}` : ''}
              </p>
              <p>
                <strong>CPU cap:</strong> {maxCpu}%
              </p>
              <p>
                <strong>Pool override:</strong>{' '}
                {poolHost.trim() ? `${poolHost.trim()}${poolPort > 0 ? `:${poolPort}` : ''}` : 'none (keep baked)'}
              </p>
            </div>
            <div className="fleet-policy-step-actions">
              <button type="button" className="btn btn-outline" onClick={() => setWizardStep(2)}>
                Back
              </button>
              <button
                type="button"
                className="btn btn-primary"
                onClick={() => void handlePushPolicy()}
                disabled={pushingPolicy || !targetReady}
              >
                {pushingPolicy ? 'Pushing…' : 'Confirm & push policy'}
              </button>
            </div>
          </div>
        )}

        {wizardStep === 4 && (
          <div className="fleet-policy-step-panel operator-interactive" aria-live="polite">
            <h3 className="fleet-policy-step-title">Step 4 — Live acknowledgements</h3>
            <div className="fleet-policy-ack-banner">
              <span className="fleet-policy-ack-count font-display">{ackCount}</span>
              <span className="fleet-policy-ack-label">
                agent{ackCount === 1 ? '' : 's'} acknowledged
                {expectedSent > 0 ? ` · ${expectedSent} dispatched` : ''}
              </span>
            </div>
            {pushId && <p className="form-hint mono-sm">push_id: {pushId}</p>}
            {policyMsg && <p className="form-hint">{policyMsg}</p>}
            <div className="fleet-policy-step-actions">
              <button type="button" className="btn btn-outline" onClick={resetWizard}>
                Push another policy
              </button>
            </div>
          </div>
        )}
      </NeonCard>

      <NeonCard accent="magenta" className="settings-section fleet-module-deck operator-deck-card operator-interactive">
        <h2 className="font-display">Push Module to Fleet <HelpTip field="fleet_runtime_modules" /></h2>
        <p className="section-desc">
          Stage signed feature packs from <code className="mono-sm">data/modules/</code> — agents fetch via{' '}
          <code className="mono-sm">GET /api/v1/agent/module/&#123;name&#125;</code> and enable flags without a full
          re-forge. Uses the same target picker as Live Fleet Policy above.
        </p>
        <div className="form-row">
          <div className="form-group">
            <label className="label" htmlFor="fleet-target-mode-module">
              Target
            </label>
            <select
              id="fleet-target-mode-module"
              className="input"
              value={targetMode}
              onChange={(e) => setTargetMode(e.target.value as TargetMode)}
            >
              <option value="all">All online ({onlineCount})</option>
              <option value="group">Fleet group</option>
            </select>
          </div>
          {targetMode === 'group' && (
            <div className="form-group">
              <label className="label" htmlFor="fleet-group-module">
                Group
              </label>
              <select id="fleet-group-module" className="input" value={groupId} onChange={(e) => setGroupId(e.target.value)}>
                <option value="">Select group…</option>
                {groups.map((g) => (
                  <option key={g.id} value={g.id}>
                    {g.name} ({g.agentIds.length})
                  </option>
                ))}
              </select>
            </div>
          )}
        </div>
        <div className="form-row">
          <div className="form-group">
            <label className="label" htmlFor="fleet-module">
              Module pack
            </label>
            <select
              id="fleet-module"
              className="input"
              value={selectedModule}
              onChange={(e) => setSelectedModule(e.target.value)}
            >
              {(modules.length ? modules : [{ name: 'crucible_ops', description: 'Remote aggressive ops' }]).map(
                (m) => (
                  <option key={m.name} value={m.name}>
                    {m.name} — {m.description || ('version' in m ? m.version : '')}
                  </option>
                ),
              )}
            </select>
          </div>
        </div>
        <button type="button" className="btn btn-outline" onClick={handlePushModule} disabled={pushingModule}>
          {pushingModule ? 'Pushing…' : 'Push module'}
        </button>
        {moduleMsg && <p className="form-hint" style={{ marginTop: '0.5rem' }}>{moduleMsg}</p>}
      </NeonCard>
    </>
  );
}
