import { useState, useMemo, useCallback } from 'react';
import { Handle, Position } from '@xyflow/react';
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';

// ─── Node Components ──────────────────────────────────────────────────────────

function RuleNode({ data }) {
  return (
    <div
      className="rounded-lg px-3 py-2 min-w-[150px] max-w-[180px] cursor-pointer select-none"
      style={{
        background: '#451a03',
        border: `1.5px solid ${data.dimmed ? '#78350f' : '#f59e0b'}`,
        boxShadow: data.dimmed ? 'none' : '0 0 8px #f59e0b33',
        opacity: data.dimmed ? 0.3 : 1,
      }}
    >
      <Handle type="source" position={Position.Right} style={{ background: '#f59e0b', width: 7, height: 7 }} />
      <div className="text-amber-100 text-xs font-semibold leading-tight truncate" title={data.label}>
        {data.label}
      </div>
      <div className="text-amber-400 text-[10px] mt-0.5">
        {data.pathCount} glob{data.pathCount !== 1 ? 's' : ''}
        {data.stacks?.length > 0 ? ` · ${data.stacks.join(', ')}` : ''}
      </div>
    </div>
  );
}

function StandardRefNode({ data }) {
  return (
    <div
      className="rounded-lg px-3 py-2 min-w-[140px] max-w-[170px] select-none cursor-default"
      style={{
        background: '#1e3a5f',
        border: `1.5px solid ${data.dimmed ? '#1e40af' : '#3b82f6'}`,
        boxShadow: data.dimmed ? 'none' : '0 0 8px #3b82f633',
        opacity: data.dimmed ? 0.3 : 1,
      }}
    >
      <Handle type="target" position={Position.Left} style={{ background: '#3b82f6', width: 7, height: 7 }} />
      <div className="text-blue-100 text-xs font-semibold leading-tight truncate" title={data.label}>
        {data.label}
      </div>
      <div className="text-blue-400 text-[10px] mt-0.5">standard ref</div>
    </div>
  );
}

const nodeTypes = { ruleNode: RuleNode, standardRefNode: StandardRefNode };

// ─── Graph Builder ────────────────────────────────────────────────────────────

function buildGraph(rules, search, stackFilter, dimmed) {
  const nodes = [];
  const edges = [];

  // Collect unique standard refs
  const allStdRefs = [...new Set(rules.flatMap((r) => r.standardRefs))];

  // Left column: rules at x=0
  const RULE_X = 0;
  const STD_X = 320;
  const ROW_H = 70;

  // Position rules
  const filteredRuleIds = new Set(
    rules
      .filter((r) => {
        const q = search.toLowerCase();
        const matchSearch = !q || r.name.toLowerCase().includes(q) || r.stacks.some((s) => s.toLowerCase().includes(q));
        const matchStack = !stackFilter || r.stacks.includes(stackFilter);
        return matchSearch && matchStack;
      })
      .map((r) => r.name)
  );

  const hasFilter = search || stackFilter;

  rules.forEach((rule, i) => {
    const isDimmed = hasFilter && !filteredRuleIds.has(rule.name);
    nodes.push({
      id: `rule-${rule.name}`,
      type: 'ruleNode',
      position: { x: RULE_X, y: i * ROW_H },
      data: {
        label: rule.name,
        pathCount: rule.paths.length,
        stacks: rule.stacks,
        ruleRef: rule,
        dimmed: isDimmed,
      },
    });
  });

  // Position standard refs in right column
  allStdRefs.forEach((ref, i) => {
    const label = ref.replace(/\.md$/, '').split('/').pop();
    nodes.push({
      id: `std-${ref}`,
      type: 'standardRefNode',
      position: { x: STD_X, y: i * ROW_H + (rules.length * ROW_H - allStdRefs.length * ROW_H) / 2 },
      data: { label, fullPath: ref, dimmed: false },
    });
  });

  // Edges: rule → its standard refs
  for (const rule of rules) {
    const isDimmed = hasFilter && !filteredRuleIds.has(rule.name);
    for (const ref of rule.standardRefs) {
      edges.push({
        id: `edge-${rule.name}-${ref}`,
        source: `rule-${rule.name}`,
        target: `std-${ref}`,
        type: 'smoothstep',
        style: {
          stroke: isDimmed ? '#374151' : '#f59e0b',
          strokeWidth: 1.2,
          opacity: isDimmed ? 0.2 : 0.6,
        },
      });
    }
  }

  return { nodes, edges };
}

// ─── Detail Content ───────────────────────────────────────────────────────────

function RuleDetail({ rule }) {
  const [showContent, setShowContent] = useState(false);
  return (
    <div className="text-sm text-gray-200 space-y-4">
      <div>
        <p className="text-gray-400 text-xs">File: <span className="font-mono text-gray-300">{rule.filename}</span></p>
      </div>

      {rule.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">
            {rule.stacks.map((s) => (
              <span key={s} className="px-2 py-0.5 bg-green-900/50 border border-green-700 rounded text-xs text-green-300">{s}</span>
            ))}
          </div>
        </div>
      )}

      {rule.paths?.length > 0 && (
        <div>
          <p className="text-gray-500 text-xs uppercase tracking-wide mb-1.5">Path Globs</p>
          <div className="space-y-1">
            {rule.paths.map((p) => (
              <code key={p} className="block px-2 py-1 bg-gray-950 border border-gray-800 rounded text-[10px] font-mono text-amber-300">{p}</code>
            ))}
          </div>
        </div>
      )}

      {rule.standardRefs?.length > 0 && (
        <div>
          <p className="text-gray-500 text-xs uppercase tracking-wide mb-1.5">Standard References</p>
          <ul className="space-y-1">
            {rule.standardRefs.map((ref) => (
              <li key={ref} className="flex items-center gap-2 text-xs">
                <span className="w-1.5 h-1.5 rounded-full bg-blue-400 flex-shrink-0" />
                <span className="font-mono text-blue-300">{ref}</span>
              </li>
            ))}
          </ul>
        </div>
      )}

      <div>
        <button
          onClick={() => setShowContent((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"
        >
          {showContent ? 'Hide Content' : 'Show Full Content'}
        </button>
        {showContent && (
          <pre className="mt-2 p-3 bg-gray-950 border border-gray-800 rounded text-[9px] text-gray-400 overflow-x-auto whitespace-pre-wrap font-mono leading-relaxed max-h-64 overflow-y-auto">
            {rule.content}
          </pre>
        )}
      </div>
    </div>
  );
}

// ─── Main Page ────────────────────────────────────────────────────────────────

export default function RulesMap() {
  const { rules } = morphData;
  const [search, setSearch] = useState('');
  const [stackFilter, setStackFilter] = useState('');
  const { panel, openPanel, closePanel } = useDetailPanel();

  const allStacks = useMemo(
    () => [...new Set(rules.flatMap((r) => r.stacks))].sort(),
    [rules]
  );

  const { nodes, edges } = useMemo(
    () => buildGraph(rules, search, stackFilter),
    [rules, search, stackFilter]
  );

  const handleNodeClick = useCallback(
    (_event, node) => {
      if (node.type === 'ruleNode') {
        const rule = node.data.ruleRef;
        if (rule) openPanel(rule.name, <RuleDetail rule={rule} />);
      }
    },
    [openPanel]
  );

  const filterConfig = [
    { name: 'stack', label: 'Stack', options: allStacks, value: stackFilter },
  ];

  return (
    <div className="flex flex-col h-full">
      <SearchFilter
        placeholder="Search rules by name or stack..."
        filters={filterConfig}
        onSearchChange={setSearch}
        onFilterChange={(name, value) => {
          if (name === 'stack') setStackFilter(value);
        }}
      />

      <div className="flex-1 relative">
        <FlowGraph
          nodes={nodes}
          edges={edges}
          nodeTypes={nodeTypes}
          onNodeClick={handleNodeClick}
          fitView
        />

        <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-4 h-4 rounded-sm" style={{ background: '#451a03', border: '1.5px solid #f59e0b' }} />
            <span className="text-gray-300">Rule file</span>
          </div>
          <div className="flex items-center gap-2">
            <span className="inline-block w-4 h-4 rounded-sm" style={{ background: '#1e3a5f', border: '1.5px solid #3b82f6' }} />
            <span className="text-gray-300">Standard reference</span>
          </div>
          <div className="flex items-center gap-2">
            <span className="inline-block w-6 border-t border-amber-400 opacity-60" />
            <span className="text-gray-400">references</span>
          </div>
        </div>

        <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">
          {rules.length} rules
        </div>
      </div>

      <DetailPanel open={panel.open} title={panel.title} onClose={closePanel}>
        {panel.content}
      </DetailPanel>
    </div>
  );
}
