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';

// Colors for skill categories (v5 — all skills in skills/core/)
const LEVEL_COLORS = {
  'core': { bg: '#134e4a', border: '#14b8a6', label: 'Core' },
};
const FALLBACK_LEVEL = { bg: '#1a2e1a', border: '#4ade80', label: 'Skill' };

// Phase color (indigo)
const PHASE_COLOR = { bg: '#1e1b4b', border: '#818cf8', text: '#e0e7ff' };

// SkillNode: teal/green border
function SkillNode({ data }) {
  const c = LEVEL_COLORS[data.level] || FALLBACK_LEVEL;
  return (
    <div
      className="rounded-lg px-3 py-2 min-w-[140px] max-w-[170px] cursor-pointer select-none"
      style={{ background: c.bg, border: `1.5px solid ${c.border}`, boxShadow: `0 0 8px ${c.border}22` }}
    >
      <Handle type="target" position={Position.Top} style={{ background: c.border, width: 7, height: 7 }} />
      <div className="text-white text-xs font-semibold leading-tight truncate" title={data.label}>
        {data.label}
      </div>
      <div className="mt-0.5 text-[10px] font-medium" style={{ color: c.border }}>
        {(LEVEL_COLORS[data.level] || FALLBACK_LEVEL).label}
      </div>
      <Handle type="source" position={Position.Bottom} style={{ background: c.border, width: 7, height: 7 }} />
    </div>
  );
}

// PhaseRefNode: indigo border, shows phase name
function PhaseRefNode({ data }) {
  return (
    <div
      className="rounded-lg px-4 py-2.5 min-w-[130px] select-none cursor-default"
      style={{ background: PHASE_COLOR.bg, border: `1.5px solid ${PHASE_COLOR.border}`, boxShadow: `0 0 8px ${PHASE_COLOR.border}33` }}
    >
      <Handle type="source" position={Position.Bottom} style={{ background: PHASE_COLOR.border, width: 7, height: 7 }} />
      <div className="text-white text-xs font-bold leading-tight truncate" title={data.label}>
        {data.label}
      </div>
      <div className="mt-0.5 text-[10px]" style={{ color: PHASE_COLOR.text }}>
        phase
      </div>
    </div>
  );
}

const nodeTypes = { skillNode: SkillNode, phaseRefNode: PhaseRefNode };

// Shorten a trigger string for use as edge label
function shortTrigger(trigger) {
  if (!trigger) return '';
  // "on:task:start" → "task:start", "/morph-proposal" → "morph-proposal"
  return trigger.replace(/^on:/, '').replace(/^\//, '');
}

// Build dagre layout for the skills graph
function buildLayout(nodes, edges) {
  const g = new dagre.graphlib.Graph();
  g.setDefaultEdgeLabel(() => ({}));
  g.setGraph({ rankdir: 'TB', nodesep: 50, ranksep: 80, marginx: 20, marginy: 20 });

  for (const n of nodes) {
    const w = n.type === 'phaseRefNode' ? 150 : 170;
    const h = n.type === 'phaseRefNode' ? 52 : 58;
    g.setNode(n.id, { width: w, height: h });
  }
  for (const e of edges) {
    g.setEdge(e.source, e.target);
  }

  dagre.layout(g);

  return nodes.map((n) => {
    const pos = g.node(n.id);
    const halfW = n.type === 'phaseRefNode' ? 75 : 85;
    const halfH = n.type === 'phaseRefNode' ? 26 : 29;
    return { ...n, position: { x: pos.x - halfW, y: pos.y - halfH } };
  });
}

// Detail panel for a skill
function SkillDetail({ skill }) {
  const c = LEVEL_COLORS[skill.level] || FALLBACK_LEVEL;

  return (
    <div className="text-sm text-gray-200 space-y-4">
      {/* Header badges */}
      <div className="flex flex-wrap gap-2">
        <span
          className="px-2 py-0.5 rounded text-xs font-bold"
          style={{ background: c.bg, color: c.border, border: `1px solid ${c.border}` }}
        >
          {c.label}
        </span>
        <span
          className={`px-2 py-0.5 rounded text-xs font-medium border ${
            skill.userInvocable
              ? 'bg-green-900/40 border-green-600 text-green-300'
              : 'bg-gray-800 border-gray-600 text-gray-400'
          }`}
        >
          {skill.userInvocable ? 'User-invocable' : 'Internal'}
        </span>
      </div>

      {/* ID */}
      <div>
        <p className="text-gray-500 text-xs uppercase tracking-wide mb-1">Skill ID</p>
        <p className="font-mono text-xs text-gray-300">{skill.id}</p>
      </div>

      {/* Description */}
      {skill.description && (
        <div>
          <p className="text-gray-500 text-xs uppercase tracking-wide mb-1">Description</p>
          <p className="text-gray-300 text-xs leading-relaxed">{skill.description}</p>
        </div>
      )}

      {/* Allowed tools */}
      {skill.allowedTools?.length > 0 && (
        <div>
          <p className="text-gray-500 text-xs uppercase tracking-wide mb-1.5">Allowed Tools</p>
          <div className="flex flex-wrap gap-1">
            {skill.allowedTools.map((t) => (
              <span key={t} className="px-1.5 py-0.5 bg-gray-800 border border-gray-600 rounded text-xs text-gray-300 font-mono">
                {t}
              </span>
            ))}
          </div>
        </div>
      )}

      {/* Full content */}
      {skill.content && (
        <div>
          <p className="text-gray-500 text-xs uppercase tracking-wide mb-1.5">Full Content</p>
          <pre className="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-72 overflow-y-auto">
            {skill.content}
          </pre>
        </div>
      )}
    </div>
  );
}

export default function SkillsLibrary() {
  const { skills, phases } = morphData;
  const [search, setSearch] = useState('');
  const [levelFilter, setLevelFilter] = useState('');
  const { panel, openPanel, closePanel } = useDetailPanel();

  // All unique levels for filter dropdown
  const allLevels = useMemo(
    () => [...new Set(skills.map((s) => s.level).filter(Boolean))].sort(),
    [skills]
  );

  // Matched skill IDs based on search + level filter
  const matchedIds = useMemo(() => {
    const q = search.toLowerCase();
    return new Set(
      skills
        .filter((s) => {
          const matchesSearch =
            !q ||
            s.name.toLowerCase().includes(q) ||
            s.id.toLowerCase().includes(q) ||
            s.description.toLowerCase().includes(q);
          const matchesLevel = !levelFilter || s.level === levelFilter;
          return matchesSearch && matchesLevel;
        })
        .map((s) => s.id)
    );
  }, [skills, search, levelFilter]);

  const hasFilter = search || levelFilter;

  // Build a map: skillId → [{ phaseId, trigger }] for all connected phases
  const skillToPhases = useMemo(() => {
    const map = new Map();
    for (const phase of phases.list) {
      for (const rs of phase.requiredSkills || []) {
        if (!rs.skill) continue;
        if (!map.has(rs.skill)) map.set(rs.skill, []);
        map.get(rs.skill).push({ phaseId: phase.id, trigger: rs.trigger });
      }
    }
    return map;
  }, [phases.list]);

  // Set of phase IDs that actually connect to at least one skill
  const connectedPhaseIds = useMemo(() => {
    const ids = new Set();
    for (const phase of phases.list) {
      if (phase.requiredSkills?.some((rs) => rs.skill)) {
        ids.add(phase.id);
      }
    }
    return ids;
  }, [phases.list]);

  // Build nodes + edges
  const { nodes: layoutNodes, edges } = useMemo(() => {
    const rawNodes = [];
    const rawEdges = [];

    // Phase nodes (top row) — only phases with required skills
    const connectedPhases = phases.list.filter((p) => connectedPhaseIds.has(p.id));
    for (const phase of connectedPhases) {
      rawNodes.push({
        id: `phase:${phase.id}`,
        type: 'phaseRefNode',
        data: {
          label: phase.displayName,
          phaseId: phase.id,
          color: PHASE_COLOR.border,
        },
        position: { x: 0, y: 0 },
      });
    }

    // Skill nodes
    for (const skill of skills) {
      const dimmed = hasFilter && !matchedIds.has(skill.id);
      const c = LEVEL_COLORS[skill.level] || FALLBACK_LEVEL;
      rawNodes.push({
        id: skill.id,
        type: 'skillNode',
        data: {
          label: skill.name,
          level: skill.level,
          skillRef: skill,
          color: c.border,
        },
        style: dimmed ? { opacity: 0.2 } : {},
        position: { x: 0, y: 0 },
      });
    }

    // Edges: phase → skill with trigger label
    const edgeIndex = new Map(); // track (phaseId,skillId) pairs to avoid duplicates
    for (const phase of phases.list) {
      for (const rs of phase.requiredSkills || []) {
        if (!rs.skill) continue;
        const key = `${phase.id}::${rs.skill}`;
        if (edgeIndex.has(key)) continue;
        edgeIndex.set(key, true);

        const label = shortTrigger(rs.trigger);
        rawEdges.push({
          id: `edge-${phase.id}-${rs.skill}`,
          source: `phase:${phase.id}`,
          target: rs.skill,
          type: 'smoothstep',
          label: label || undefined,
          labelStyle: { fontSize: 9, fill: '#94a3b8' },
          labelBgStyle: { fill: '#0f172a', fillOpacity: 0.85 },
          labelBgPadding: [3, 2],
          style: { stroke: PHASE_COLOR.border, strokeWidth: 1.5, opacity: 0.7 },
        });
      }
    }

    const layouted = buildLayout(rawNodes, rawEdges);
    return { nodes: layouted, edges: rawEdges };
  }, [skills, phases.list, matchedIds, hasFilter, connectedPhaseIds]);

  const handleNodeClick = useCallback(
    (_event, node) => {
      if (node.type === 'phaseRefNode') {
        // No detail panel for phase nodes per spec
        return;
      }
      const skill = node.data.skillRef;
      if (skill) {
        openPanel(skill.name, <SkillDetail skill={skill} />);
      }
    },
    [openPanel]
  );

  const filterConfig = [
    { name: 'level', label: 'Level', options: allLevels, value: levelFilter },
  ];

  // Unconnected skill count
  const unconnectedCount = useMemo(
    () => skills.filter((s) => !skillToPhases.has(s.id)).length,
    [skills, skillToPhases]
  );

  return (
    <div className="flex flex-col h-full">
      <SearchFilter
        placeholder="Search skills by name or description..."
        filters={filterConfig}
        onSearchChange={setSearch}
        onFilterChange={(name, value) => {
          if (name === 'level') setLevelFilter(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-2 z-10">
          <p className="text-gray-400 font-semibold uppercase tracking-wide text-[10px] mb-2">Legend</p>
          <div className="flex items-center gap-2">
            <span
              className="inline-block w-10 h-4 rounded-sm flex-shrink-0"
              style={{ background: PHASE_COLOR.bg, border: `1.5px solid ${PHASE_COLOR.border}` }}
            />
            <span className="text-gray-300">Phase</span>
          </div>
          {Object.entries(LEVEL_COLORS).map(([level, c]) => (
            <div key={level} className="flex items-center gap-2">
              <span
                className="inline-block w-10 h-4 rounded-sm flex-shrink-0"
                style={{ background: c.bg, border: `1.5px solid ${c.border}` }}
              />
              <span className="text-gray-300">{c.label}</span>
            </div>
          ))}
          <div className="border-t border-gray-700 mt-2 pt-2">
            <div className="flex items-center gap-2">
              <span className="inline-block w-6 border-t-2 border-indigo-400" style={{ opacity: 0.7 }} />
              <span className="text-gray-400">phase → skill</span>
            </div>
          </div>
        </div>

        {/* Stats 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 space-y-0.5">
          <div>
            {hasFilter ? `${matchedIds.size} / ${skills.length}` : skills.length} skills
          </div>
          {unconnectedCount > 0 && (
            <div className="text-gray-600">{unconnectedCount} unlinked</div>
          )}
        </div>
      </div>

      <DetailPanel open={panel.open} title={panel.title} onClose={closePanel}>
        {panel.content}
      </DetailPanel>
    </div>
  );
}
