import { useState, useMemo, useCallback } from 'react';
import { Handle, Position } from '@xyflow/react';
import dagre from '@dagrejs/dagre';
import morphData from 'virtual:morph-data';
import FlowGraph from '../components/FlowGraph.jsx';
import DetailPanel from '../components/DetailPanel.jsx';
import SearchFilter from '../components/SearchFilter.jsx';
import { useDetailPanel } from '../hooks/useDetailPanel.js';

// Domain persona color palette (v5 — flat, no tiers)
const PERSONA_COLORS = {
  user:           { bg: '#78350f', border: '#f59e0b', label: 'User' },
  'dotnet-senior':{ bg: '#991b1b', border: '#ef4444', label: 'Backend' },
  'ef-modeler':   { bg: '#7c2d12', border: '#fb923c', label: 'Data' },
  'maf-expert':   { bg: '#1e3a5f', border: '#38bdf8', label: 'Agents' },
  'nextjs-expert':{ bg: '#064e3b', border: '#34d399', label: 'Frontend' },
  'ui-designer':  { bg: '#4a1d96', border: '#a78bfa', label: 'Design' },
  'infra-engineer':{ bg: '#1e3a5f', border: '#60a5fa', label: 'Infra' },
  'evaluator':    { bg: '#374151', border: '#9ca3af', label: 'Eval' },
};
const FALLBACK_PERSONA = { bg: '#1e40af', border: '#3b82f6', label: 'Persona' };

// Custom AgentNode component
function AgentNode({ data }) {
  const colors = data.isUser ? PERSONA_COLORS.user : (PERSONA_COLORS[data.personaId] || FALLBACK_PERSONA);
  return (
    <div
      className="rounded-lg px-3 py-2 min-w-[130px] max-w-[160px] cursor-pointer select-none"
      style={{ background: colors.bg, border: `1.5px solid ${colors.border}`, boxShadow: `0 0 8px ${colors.border}22` }}
    >
      <Handle type="target" position={Position.Top} style={{ background: colors.border, width: 8, height: 8 }} />
      <div className="text-white text-xs font-semibold leading-tight truncate" title={data.label}>
        {data.label}
      </div>
      <div className="text-gray-300 text-[10px] mt-0.5 truncate">
        {data.isUser ? 'Principal' : `${colors.label} · ${data.domains?.[0] || ''}`}
      </div>
      <Handle type="source" position={Position.Bottom} style={{ background: colors.border, width: 8, height: 8 }} />
    </div>
  );
}

const nodeTypes = { agentNode: AgentNode };

// Dagre layout helpers
function buildLayout(nodes, edges) {
  const g = new dagre.graphlib.Graph();
  g.setDefaultEdgeLabel(() => ({}));
  g.setGraph({ rankdir: 'TB', nodesep: 40, ranksep: 60, marginx: 20, marginy: 20 });

  nodes.forEach((n) => g.setNode(n.id, { width: 160, height: 60 }));
  edges.forEach((e) => g.setEdge(e.source, e.target));

  dagre.layout(g);

  return nodes.map((n) => {
    const pos = g.node(n.id);
    return { ...n, position: { x: pos.x - 80, y: pos.y - 30 } };
  });
}

// AgentDetail shown inside the panel
function AgentDetail({ agent }) {
  const [showPrompt, setShowPrompt] = useState(false);
  const personaColors = PERSONA_COLORS[agent.id] || FALLBACK_PERSONA;

  return (
    <div className="text-sm text-gray-200 space-y-4">
      {/* Header */}
      <div>
        <div className="flex items-center gap-2 mb-1">
          <span className="px-2 py-0.5 rounded text-xs font-bold" style={{ background: personaColors.bg, color: personaColors.border, border: `1px solid ${personaColors.border}` }}>
            {personaColors.label}
          </span>
          <span className="text-gray-400 text-xs">{agent.domains?.[0] || ''}</span>
        </div>
        <p className="text-gray-400 text-xs">ID: <span className="text-gray-300 font-mono">{agent.id}</span></p>
      </div>

      {/* Active Phases */}
      {agent.activePhases?.length > 0 && (
        <div>
          <p className="text-gray-500 text-xs uppercase tracking-wide mb-1.5">Active Phases</p>
          <div className="flex flex-wrap gap-1">
            {agent.activePhases.map((p) => (
              <span key={p} className="px-2 py-0.5 bg-blue-900/50 border border-blue-700 rounded text-xs text-blue-300">{p}</span>
            ))}
          </div>
        </div>
      )}

      {/* Validators */}
      {agent.validators?.length > 0 && (
        <div>
          <p className="text-gray-500 text-xs uppercase tracking-wide mb-1.5">Validators</p>
          <div className="flex flex-wrap gap-1">
            {agent.validators.map((v) => (
              <span key={v} className="px-2 py-0.5 bg-purple-900/50 border border-purple-700 rounded text-xs text-purple-300">{v}</span>
            ))}
          </div>
        </div>
      )}

      {/* Standards */}
      {agent.standards?.length > 0 && (
        <div>
          <p className="text-gray-500 text-xs uppercase tracking-wide mb-1.5">Standards</p>
          <ul className="space-y-1">
            {agent.standards.map((s) => (
              <li key={s.id} className="flex items-center justify-between text-xs">
                <span className="font-mono text-gray-300">{s.id}</span>
                <div className="flex gap-1">
                  {s.scope && <span className="px-1.5 py-0.5 bg-gray-800 rounded text-gray-400">{s.scope}</span>}
                  {s.priority && <span className="px-1.5 py-0.5 bg-gray-800 rounded text-gray-400">{s.priority}</span>}
                </div>
              </li>
            ))}
          </ul>
        </div>
      )}

      {/* Domains */}
      {agent.domains?.length > 0 && (
        <div>
          <p className="text-gray-500 text-xs uppercase tracking-wide mb-1.5">Domains</p>
          <p className="text-gray-300 text-xs">{agent.domains.join(', ')}</p>
        </div>
      )}

      {/* Keywords */}
      {agent.keywords?.length > 0 && (
        <div>
          <p className="text-gray-500 text-xs uppercase tracking-wide mb-1.5">Keywords</p>
          <div className="flex flex-wrap gap-1">
            {agent.keywords.map((k) => (
              <span key={k} className="px-1.5 py-0.5 bg-gray-800 border border-gray-700 rounded text-xs text-gray-400">{k}</span>
            ))}
          </div>
        </div>
      )}

      {/* Stacks */}
      {agent.stacks?.length > 0 && (
        <div>
          <p className="text-gray-500 text-xs uppercase tracking-wide mb-1.5">Stacks</p>
          <div className="flex flex-wrap gap-1">
            {agent.stacks.map((s) => (
              <span key={s} className="px-1.5 py-0.5 bg-green-900/50 border border-green-700 rounded text-xs text-green-300">{s}</span>
            ))}
          </div>
        </div>
      )}

      {/* Full Prompt toggle */}
      {agent.prompt && (
        <div>
          <button
            onClick={() => setShowPrompt((v) => !v)}
            className="w-full text-left px-3 py-1.5 bg-gray-800 hover:bg-gray-700 border border-gray-700 rounded text-xs text-gray-300 transition-colors"
          >
            {showPrompt ? 'Hide Full Prompt' : 'Show Full Prompt'}
          </button>
          {showPrompt && (
            <pre className="mt-2 p-3 bg-gray-950 border border-gray-800 rounded text-[10px] text-gray-400 overflow-x-auto whitespace-pre-wrap font-mono leading-relaxed max-h-64 overflow-y-auto">
              {agent.prompt}
            </pre>
          )}
        </div>
      )}
    </div>
  );
}

export default function AgentMap() {
  const { agents } = morphData;
  const [search, setSearch] = useState('');
  const [domainFilter, setDomainFilter] = useState('');
  const [groupFilter, setGroupFilter] = useState('');
  const [phaseFilter, setPhaseFilter] = useState('');
  const [stackFilter, setStackFilter] = useState('');
  const { panel, openPanel, closePanel } = useDetailPanel();

  // Derive unique groups, tiers, phases, and stacks for filters
  const allGroups = useMemo(() => [...new Set(agents.list.map((a) => a.domains?.[0]).filter(Boolean))].sort(), [agents.list]);
  const allDomains = useMemo(() => [...new Set(agents.list.flatMap((a) => a.domains || []))].sort(), [agents.list]);
  const allPhases = useMemo(() => {
    const phases = new Set();
    for (const a of agents.list) {
      for (const p of a.activePhases || []) {
        if (p !== '*') phases.add(p);
      }
    }
    return [...phases].sort();
  }, [agents.list]);
  const allStacks = useMemo(() => {
    const stacks = new Set();
    for (const a of agents.list) {
      for (const s of a.stacks || []) {
        stacks.add(s);
      }
    }
    return [...stacks].sort();
  }, [agents.list]);

  // Filtered agent ids (for highlight — we always show all nodes but dim non-matching)
  const matchedIds = useMemo(() => {
    const q = search.toLowerCase();
    return new Set(
      agents.list
        .filter((a) => {
          const matchesSearch = !q || a.title.toLowerCase().includes(q) || a.id.toLowerCase().includes(q) || a.keywords?.some((k) => k.toLowerCase().includes(q));
          const matchesDomain = !domainFilter || (a.domains || []).includes(domainFilter);
          const matchesGroup = !groupFilter || (a.domains || []).includes(groupFilter);
          const matchesPhase = !phaseFilter || (a.activePhases || []).includes('*') || (a.activePhases || []).includes(phaseFilter);
          const matchesStack = !stackFilter || (a.stacks || []).includes(stackFilter);
          return matchesSearch && matchesDomain && matchesGroup && matchesPhase && matchesStack;
        })
        .map((a) => a.id)
    );
  }, [agents.list, search, tierFilter, groupFilter, phaseFilter, stackFilter]);

  const hasFilter = search || domainFilter || groupFilter || phaseFilter || stackFilter;

  // Build React Flow nodes and edges
  const { nodes: layoutNodes, edges } = useMemo(() => {
    const rawNodes = [];
    const rawEdges = [];

    // User node at top
    rawNodes.push({
      id: '__user__',
      type: 'agentNode',
      data: { label: 'User', isUser: true, color: '#78350f' },
      position: { x: 0, y: 0 },
    });

    // Agent nodes
    for (const agent of agents.list) {
      const dimmed = hasFilter && !matchedIds.has(agent.id);
      const personaColors = PERSONA_COLORS[agent.id] || FALLBACK_PERSONA;
      rawNodes.push({
        id: agent.id,
        type: 'agentNode',
        data: {
          label: agent.title,
          personaId: agent.id,
          domains: agent.domains,
          color: personaColors.border,
          agentRef: agent,
        },
        style: dimmed ? { opacity: 0.2 } : {},
        position: { x: 0, y: 0 },
      });
    }

    // user → agent edges (flat — no hierarchy in v5)
    for (const agent of agents.list) {
      const personaColors = PERSONA_COLORS[agent.id] || FALLBACK_PERSONA;
      rawEdges.push({
        id: `rt-${agent.id}`,
        source: '__user__',
        target: agent.id,
        type: 'smoothstep',
        style: { stroke: personaColors.border, strokeWidth: 1.5 },
        animated: false,
      });
    }

    // validators edges (dashed purple) — Tier 4 validator agent → validated agent
    // agent.validators contains runner names like "architecture", "design-system", "nextjs-component"
    // which map to Tier 4 agent IDs like "architecture-expert", "design-system-validator", etc.
    // Match by finding the Tier 4 agent whose ID contains the validator runner name.
    const tier4Agents = agents.list.filter((a) => a.tier === 4);
    for (const agent of agents.list) {
      for (const v of agent.validators || []) {
        const validatorAgent = tier4Agents.find((a) => a.id.includes(v));
        if (validatorAgent) {
          rawEdges.push({
            id: `val-${validatorAgent.id}-${agent.id}`,
            source: validatorAgent.id,
            target: agent.id,
            type: 'smoothstep',
            style: { stroke: '#8b5cf6', strokeWidth: 1, strokeDasharray: '4 3' },
            animated: false,
          });
        }
      }
    }

    const layouted = buildLayout(rawNodes, rawEdges);
    return { nodes: layouted, edges: rawEdges };
  }, [agents.list, matchedIds, hasFilter]);

  const handleNodeClick = useCallback(
    (_event, node) => {
      if (node.id === '__user__') {
        openPanel('User (Principal)', <div className="text-gray-400 text-sm">The human operator. All Tier 1 orchestrators report to this node.</div>);
        return;
      }
      const agent = node.data.agentRef;
      if (agent) {
        openPanel(agent.title, <AgentDetail agent={agent} />);
      }
    },
    [openPanel]
  );

  const filterConfig = [
    { name: 'tier', label: 'Tier', options: allTiers, value: tierFilter },
    { name: 'group', label: 'Group', options: allGroups, value: groupFilter },
    { name: 'phase', label: 'Phase', options: allPhases, value: phaseFilter },
    { name: 'stack', label: 'Stack', options: allStacks, value: stackFilter },
  ];

  return (
    <div className="flex flex-col h-full">
      <SearchFilter
        placeholder="Search agents by name or keyword..."
        filters={filterConfig}
        onSearchChange={setSearch}
        onFilterChange={(name, value) => {
          if (name === 'tier') setTierFilter(value);
          if (name === 'group') setGroupFilter(value);
          if (name === 'phase') setPhaseFilter(value);
          if (name === 'stack') setStackFilter(value);
        }}
      />

      <div className="flex-1 relative">
        <FlowGraph
          nodes={layoutNodes}
          edges={edges}
          nodeTypes={nodeTypes}
          onNodeClick={handleNodeClick}
          fitView
        />

        {/* Legend */}
        <div className="absolute top-3 left-3 bg-gray-900/90 border border-gray-700 rounded-lg p-3 text-xs space-y-1.5 z-10">
          <p className="text-gray-400 font-semibold uppercase tracking-wide text-[10px] mb-2">Legend</p>
          {Object.entries(TIER_COLORS).map(([key, c]) => (
            <div key={key} className="flex items-center gap-2">
              <span className="inline-block w-3 h-3 rounded-sm flex-shrink-0" style={{ background: c.bg, border: `1px solid ${c.border}` }} />
              <span className="text-gray-300">{key === 'user' ? 'User' : `Tier ${key} — ${c.label}`}</span>
            </div>
          ))}
          <div className="border-t border-gray-700 mt-2 pt-2 space-y-1">
            <div className="flex items-center gap-2">
              <span className="inline-block w-6 border-t-2 border-blue-400" />
              <span className="text-gray-400">reports_to</span>
            </div>
            <div className="flex items-center gap-2">
              <span className="inline-block w-6 border-t-2 border-purple-400 border-dashed" />
              <span className="text-gray-400">validates</span>
            </div>
          </div>
        </div>

        {/* Agent count badge */}
        <div className="absolute top-3 right-3 bg-gray-900/90 border border-gray-700 rounded-lg px-3 py-1.5 text-xs text-gray-400 z-10">
          {hasFilter ? `${matchedIds.size} / ${agents.list.length}` : agents.list.length} agents
        </div>
      </div>

      <DetailPanel open={panel.open} title={panel.title} onClose={closePanel}>
        {panel.content}
      </DetailPanel>
    </div>
  );
}
