import { useState, useEffect, useRef, useCallback } from 'react';
import { fetchCausal } from '../api';

const GROUP_COLORS = {
  Price: '#3b82f6', Supply: '#10b981', Demand: '#f59e0b',
  Risk_Geo: '#ef4444', Technical: '#8b5cf6', Alternative: '#06b6d4', Target: '#ff6b6b',
};
const GROUP_ZH = {
  Price: '价格', Supply: '供给', Demand: '需求',
  Risk_Geo: '风险/地缘', Technical: '技术面', Alternative: '另类数据', Target: '目标',
};
const FEAT_ZH = {
  Brent_spot: 'Brent', vix_lag1: 'VIX', rsi12m: 'RSI',
  vix_lag2: 'VIX(L2)', mom1m_lag1: '动量', hist_vol_12m: '历史波动率',
  usd_index: 'USD指数', iron_ore_spot: '铁矿石', rig_count_us_new: '钻井数',
  ipi_us: '工业产出', natgas_spot_henry: '天然气', nonfarm_us: '非农就业',
  supply_saudi: '沙特产量', pmi_us_mfg: 'PMI制造业', target_ret_1m: '油价收益率',
  news_oil_sentiment: '新闻情绪', news_geo_tone: '地缘情绪', news_article_volume: '新闻量',
};

/* Simple force layout — runs once on data load */
function layoutNodes(nodes, edges, W, H) {
  const cx = W / 2, cy = H / 2;
  // Place target at center
  const targetIdx = nodes.findIndex(n => n.id === 'target_ret_1m');
  if (targetIdx >= 0) { nodes[targetIdx].x = cx; nodes[targetIdx].y = cy; }
  // Others in a circle around center
  const others = nodes.filter(n => n.id !== 'target_ret_1m');
  const r = Math.min(W, H) * 0.38;
  others.forEach((n, i) => {
    const angle = (2 * Math.PI * i) / others.length - Math.PI / 2;
    n.x = cx + r * Math.cos(angle);
    n.y = cy + r * Math.sin(angle);
  });

  // Simple force iterations
  for (let iter = 0; iter < 60; iter++) {
    // Repulsion
    for (let i = 0; i < nodes.length; i++) {
      for (let j = i + 1; j < nodes.length; j++) {
        const dx = nodes[j].x - nodes[i].x;
        const dy = nodes[j].y - nodes[i].y;
        const dist = Math.sqrt(dx * dx + dy * dy) || 1;
        const force = 800 / (dist * dist);
        const fx = (dx / dist) * force;
        const fy = (dy / dist) * force;
        if (nodes[i].id !== 'target_ret_1m') { nodes[i].x -= fx; nodes[i].y -= fy; }
        if (nodes[j].id !== 'target_ret_1m') { nodes[j].x += fx; nodes[j].y += fy; }
      }
    }
    // Attraction for edges
    edges.forEach(e => {
      const src = nodes.find(n => n.id === e.source);
      const tgt = nodes.find(n => n.id === e.target);
      if (!src || !tgt) return;
      const dx = tgt.x - src.x;
      const dy = tgt.y - src.y;
      const dist = Math.sqrt(dx * dx + dy * dy) || 1;
      const force = (dist - 120) * 0.01 * (e.strength || 0.5);
      const fx = (dx / dist) * force;
      const fy = (dy / dist) * force;
      if (src.id !== 'target_ret_1m') { src.x += fx; src.y += fy; }
      if (tgt.id !== 'target_ret_1m') { tgt.x += fx; tgt.y += fy; }
    });
    // Bounds
    nodes.forEach(n => {
      n.x = Math.max(55, Math.min(W - 55, n.x));
      n.y = Math.max(30, Math.min(H - 30, n.y));
    });
  }
  return nodes;
}

export default function CausalGraph() {
  const [data, setData] = useState(null);
  const [hovered, setHovered] = useState(null);
  const W = 680, H = 440;

  useEffect(() => {
    fetchCausal().then(d => {
      if (!d || !d.network) return;
      // Build nodes
      const nodeMap = {};
      // Target node
      nodeMap['target_ret_1m'] = { id: 'target_ret_1m', group: 'Target', label: '油价收益率', size: 22 };
      // Feature nodes from ranking
      (d.ranking || []).forEach(r => {
        nodeMap[r.feature] = {
          id: r.feature, group: r.group,
          label: FEAT_ZH[r.feature] || r.feature,
          size: 10 + (r.causal_strength || 0) * 3,
          strength: r.causal_strength,
          pValue: r.granger_p,
          isCausal: r.is_causal === 'True',
        };
      });
      // Edges: feature → target
      const edges = [];
      (d.network.feature_to_target || []).forEach(e => {
        if (!nodeMap[e.cause]) return;
        edges.push({
          source: e.cause, target: 'target_ret_1m',
          pValue: e.p_value, significant: e.significant === 'True',
          lag: e.best_lag, type: 'to_target',
          strength: e.significant === 'True' ? 1 : 0.3,
        });
      });
      // Edges: inter-feature (only significant ones, p < 0.05)
      (d.network.inter_feature || []).forEach(e => {
        if (!nodeMap[e.cause] || !nodeMap[e.effect]) return;
        if (e.p_value > 0.05) return;
        edges.push({
          source: e.cause, target: e.effect,
          pValue: e.p_value, significant: true,
          lag: e.best_lag, type: 'inter',
          strength: 0.5,
        });
      });

      const nodes = Object.values(nodeMap);
      layoutNodes(nodes, edges, W, H);
      setData({ nodes, edges, groupStrength: d.group_strength });
    }).catch(() => {});
  }, []);

  if (!data) return null;
  const { nodes, edges, groupStrength } = data;

  const getNode = id => nodes.find(n => n.id === id);

  return (
    <div className="card" style={{ padding: '1.2rem' }}>
      <h3>🔗 因果因子网络 <span style={{ fontSize: '.75rem', fontWeight: 400, color: 'var(--muted)' }}>Granger Causality Network</span></h3>
      <p style={{ fontSize: '.8rem', color: 'var(--muted)', margin: '.3rem 0 .8rem' }}>
        节点大小 = 因果强度 · 实线 = 显著因果关系(p&lt;0.05) · 虚线 = 非显著 · 箭头方向 = 因果方向
      </p>
      <div style={{ display: 'flex', gap: '1.5rem' }}>
        <svg width={W} height={H} style={{ background: 'rgba(0,0,0,.15)', borderRadius: '.6rem', flexShrink: 0 }}>
          <defs>
            <marker id="arrow-sig" viewBox="0 0 10 6" refX="10" refY="3" markerWidth="8" markerHeight="6" orient="auto-start-reverse">
              <path d="M0,0 L10,3 L0,6 Z" fill="rgba(255,255,255,.6)" />
            </marker>
            <marker id="arrow-inter" viewBox="0 0 10 6" refX="10" refY="3" markerWidth="7" markerHeight="5" orient="auto-start-reverse">
              <path d="M0,0 L10,3 L0,6 Z" fill="rgba(139,92,246,.4)" />
            </marker>
          </defs>

          {/* Edges */}
          {edges.map((e, i) => {
            const src = getNode(e.source);
            const tgt = getNode(e.target);
            if (!src || !tgt) return null;
            const isHighlight = hovered && (hovered === e.source || hovered === e.target);
            const isTarget = e.type === 'to_target';
            const opacity = hovered ? (isHighlight ? 1 : 0.1) : (e.significant ? 0.7 : 0.25);
            return (
              <line key={i}
                x1={src.x} y1={src.y} x2={tgt.x} y2={tgt.y}
                stroke={isTarget ? (e.significant ? '#ff6b6b' : '#556688') : 'rgba(139,92,246,.3)'}
                strokeWidth={e.significant ? 2 : 1}
                strokeDasharray={e.significant ? '' : '4,3'}
                opacity={opacity}
                markerEnd={isTarget ? 'url(#arrow-sig)' : 'url(#arrow-inter)'}
              />
            );
          })}

          {/* Nodes */}
          {nodes.map(n => {
            const isHighlight = !hovered || hovered === n.id || edges.some(e => (e.source === hovered && e.target === n.id) || (e.target === hovered && e.source === n.id));
            const color = GROUP_COLORS[n.group] || '#888';
            return (
              <g key={n.id}
                onMouseEnter={() => setHovered(n.id)}
                onMouseLeave={() => setHovered(null)}
                style={{ cursor: 'pointer' }}
                opacity={isHighlight ? 1 : 0.2}
              >
                {n.isCausal && (
                  <circle cx={n.x} cy={n.y} r={n.size + 4}
                    fill="none" stroke={color} strokeWidth={2} opacity={0.4} />
                )}
                <circle cx={n.x} cy={n.y} r={n.size}
                  fill={color} stroke="#0d1117" strokeWidth={1.5}
                  opacity={n.id === 'target_ret_1m' ? 1 : 0.85} />
                <text x={n.x} y={n.y + n.size + 13}
                  textAnchor="middle" fill="var(--text)" fontSize={n.id === 'target_ret_1m' ? 11 : 9.5}
                  fontWeight={n.id === 'target_ret_1m' ? 700 : 400}>
                  {n.label}
                </text>
              </g>
            );
          })}

          {/* Hover tooltip */}
          {hovered && (() => {
            const n = getNode(hovered);
            if (!n || n.id === 'target_ret_1m') return null;
            const tx = Math.min(n.x + 15, W - 140);
            const ty = Math.max(n.y - 40, 15);
            return (
              <g>
                <rect x={tx} y={ty} width={130} height={48} rx={6} fill="rgba(13,17,23,.92)" stroke="rgba(99,102,241,.4)" />
                <text x={tx + 8} y={ty + 16} fill="#e2e8f0" fontSize={10} fontWeight={600}>{n.label}</text>
                <text x={tx + 8} y={ty + 30} fill="#94a3b8" fontSize={9}>
                  p={n.pValue?.toFixed(4)} | 强度={n.strength?.toFixed(2)}
                </text>
                <text x={tx + 8} y={ty + 42} fill={n.isCausal ? '#10b981' : '#ef4444'} fontSize={9} fontWeight={600}>
                  {n.isCausal ? '✓ 显著因果' : '✗ 非显著'}
                </text>
              </g>
            );
          })()}
        </svg>

        {/* Legend & Group Strength */}
        <div style={{ flex: 1, minWidth: 0 }}>
          <h4 style={{ fontSize: '.85rem', marginBottom: '.6rem', color: 'var(--accent)' }}>因子组因果强度</h4>
          {groupStrength && Object.entries(groupStrength)
            .sort((a, b) => b[1].total_strength - a[1].total_strength)
            .map(([group, gs]) => (
              <div key={group} style={{ marginBottom: '.7rem' }}>
                <div style={{ display: 'flex', justifyContent: 'space-between', fontSize: '.8rem', marginBottom: '.2rem' }}>
                  <span style={{ color: GROUP_COLORS[group] }}>{GROUP_ZH[group] || group}</span>
                  <span style={{ color: 'var(--muted)' }}>
                    {gs.n_causal}/{gs.n_total} 显著 · 强度 {gs.total_strength.toFixed(1)}
                  </span>
                </div>
                <div style={{ height: 6, background: 'rgba(255,255,255,.06)', borderRadius: 3, overflow: 'hidden' }}>
                  <div style={{
                    width: `${Math.min(gs.total_strength / 4 * 100, 100)}%`,
                    height: '100%', borderRadius: 3,
                    background: `linear-gradient(90deg, ${GROUP_COLORS[group]}55, ${GROUP_COLORS[group]})`,
                  }} />
                </div>
              </div>
            ))
          }
          <div style={{ marginTop: '1rem', fontSize: '.75rem', color: 'var(--muted)', lineHeight: 1.6 }}>
            <div style={{ fontWeight: 600, marginBottom: '.3rem', color: 'var(--text)' }}>图例</div>
            <div><span style={{ color: '#ff6b6b' }}>━━</span> 显著因果 → 目标</div>
            <div><span style={{ color: '#556688' }}>╌╌</span> 非显著 → 目标</div>
            <div><span style={{ color: '#8b5cf6' }}>━━</span> 因子间因果</div>
            <div>◉ 外环 = 通过显著性检验</div>
          </div>
        </div>
      </div>
    </div>
  );
}
