import { useMemo, useState, useRef, useCallback } from 'react';

/* ── Palette ────────────────────────────────────────────────── */
const PALETTE = [
  '#e8547a', '#9333ea', '#0d9488', '#f59e0b',
  '#3b82f6', '#10b981', '#f97316', '#06b6d4',
  '#a855f7', '#84cc16', '#ec4899', '#14b8a6',
];

/* ── Algorithme treemap (binary split équilibré) ────────────── */
function buildTreemap(items, x, y, w, h) {
  if (!items.length) return [];
  if (items.length === 1) return [{ ...items[0], x, y, w, h }];

  const total = items.reduce((s, i) => s + i.value, 0);
  let best = 1, bestDiff = Infinity, acc = 0;
  for (let i = 0; i < items.length - 1; i++) {
    acc += items[i].value;
    const diff = Math.abs(acc - (total - acc));
    if (diff < bestDiff) { bestDiff = diff; best = i + 1; }
  }

  const g1 = items.slice(0, best);
  const g2 = items.slice(best);
  const r1 = g1.reduce((s, i) => s + i.value, 0) / total;

  if (w >= h) {
    const w1 = w * r1;
    return [
      ...buildTreemap(g1, x, y, w1, h),
      ...buildTreemap(g2, x + w1, y, w - w1, h),
    ];
  } else {
    const h1 = h * r1;
    return [
      ...buildTreemap(g1, x, y, w, h1),
      ...buildTreemap(g2, x, y + h1, w, h - h1),
    ];
  }
}

/* ── Formatage : nombre entier arrondi, jamais de k€ ── */
function fmtAmount(v) {
  return Math.round(v).toLocaleString('fr-FR') + ' €';
}

/* ── Word-wrap SVG : découpe un nom en lignes selon la largeur dispo ── */
function wrapText(text, maxWidth, fontSize) {
  const charW = fontSize * 0.58; // largeur approx d'un caractère
  const maxChars = Math.max(1, Math.floor(maxWidth / charW));
  const words = text.split(' ');
  const lines = [];
  let current = '';
  for (const word of words) {
    const candidate = current ? current + ' ' + word : word;
    if (candidate.length <= maxChars) {
      current = candidate;
    } else {
      if (current) lines.push(current);
      current = word.length > maxChars ? word.slice(0, maxChars - 1) + '…' : word;
    }
  }
  if (current) lines.push(current);
  return lines.slice(0, 3); // max 3 lignes
}

/* ── Composant ──────────────────────────────────────────────── */
export default function DistributionChart({ rows }) {
  const [hoveredIdx, setHoveredIdx] = useState(null);
  const [tooltip,    setTooltip]    = useState(null); // { x, y, cell }
  const svgRef  = useRef(null);
  const wrapRef = useRef(null);

  /* Solde net par plateforme */
  const { data, allRetraits } = useMemo(() => {
    if (!rows?.length) return { data: [], allRetraits: false };
    const allRetraits = rows.every(r => r.type === 'retrait');
    const byPlat = {};
    for (const r of rows) {
      const key = r.plateforme_nom || `#${r.plateforme_id}`;
      byPlat[key] = (byPlat[key] || 0) + r.montant;
    }
    const data = Object.entries(byPlat)
      .filter(([, v]) => v > 0)
      .sort(([, a], [, b]) => b - a)
      .map(([name, value], i) => ({ name, value, color: PALETTE[i % PALETTE.length] }));
    return { data, allRetraits };
  }, [rows]);

  const total = data.reduce((s, i) => s + i.value, 0);

  const W = 440, H = 290, GAP = 3;

  const cells = useMemo(() => buildTreemap(data, 0, 0, W, H), [data]);

  /* Conversion coordonnées SVG → pixels dans le wrapper */
  const handleMouseMove = useCallback((e, cell, idx) => {
    if (!svgRef.current || !wrapRef.current) return;
    const svgRect  = svgRef.current.getBoundingClientRect();
    const wrapRect = wrapRef.current.getBoundingClientRect();
    // Position relative au wrapper (pour le tooltip absolu)
    const tx = e.clientX - wrapRect.left;
    const ty = e.clientY - wrapRect.top;
    setHoveredIdx(idx);
    setTooltip({ x: tx, y: ty, cell });
  }, []);

  const handleMouseLeave = useCallback(() => {
    setHoveredIdx(null);
    setTooltip(null);
  }, []);

  if (!cells.length) return null;

  /* Position tooltip : évite les débordements */
  const TIP_W = 150, TIP_H = 66;
  const tipStyle = tooltip ? (() => {
    const ww = wrapRef.current?.offsetWidth || 400;
    const wh = wrapRef.current?.offsetHeight || 360;
    let tx = tooltip.x + 14;
    let ty = tooltip.y - TIP_H / 2;
    if (tx + TIP_W > ww - 4) tx = tooltip.x - TIP_W - 14;
    if (ty < 4) ty = 4;
    if (ty + TIP_H > wh - 4) ty = wh - TIP_H - 4;
    return { left: tx, top: ty };
  })() : null;

  return (
    <div className="dist-chart-wrap" ref={wrapRef}>

      {/* ── En-tête ── */}
      <div className="dist-chart-header">
        <span className="dist-chart-title">Distribution</span>
        <div className="dist-dropdown">
          par Plateforme
          <svg width="10" height="10" viewBox="0 0 24 24" fill="none"
            stroke="currentColor" strokeWidth="2.5" strokeLinecap="round" strokeLinejoin="round">
            <path d="M6 9l6 6 6-6"/>
          </svg>
        </div>
      </div>

      {/* ── Treemap SVG ── */}
      <div style={{ position: 'relative' }}>
        <svg
          ref={svgRef}
          viewBox={`0 0 ${W} ${H}`}
          style={{ width: '100%', height: 'auto', display: 'block' }}
          onMouseLeave={handleMouseLeave}
        >
          <defs>
            <linearGradient id="dt-shadow" x1="0" y1="0" x2="0" y2="1">
              <stop offset="0%"   stopColor="#000" stopOpacity="0" />
              <stop offset="100%" stopColor="#000" stopOpacity="0.4" />
            </linearGradient>
            <filter id="dt-txt-shadow" x="-20%" y="-20%" width="140%" height="140%">
              <feDropShadow dx="0" dy="1" stdDeviation="1.5" floodColor="#000" floodOpacity="0.55"/>
            </filter>
            {/* clipPath par cellule — défini dynamiquement dans chaque <g> */}
            {cells.map((cell, i) => {
              const PAD = 4;
              const gx = cell.x + GAP / 2 + PAD;
              const gy = cell.y + GAP / 2 + PAD;
              const gw = Math.max(cell.w - GAP - PAD * 2, 0);
              const gh = Math.max(cell.h - GAP - PAD * 2, 0);
              return (
                <clipPath key={i} id={`clip-${i}`}>
                  <rect x={gx} y={gy} width={gw} height={gh} />
                </clipPath>
              );
            })}
          </defs>

          {cells.map((cell, i) => {
            const gx = cell.x + GAP / 2;
            const gy = cell.y + GAP / 2;
            const gw = Math.max(cell.w - GAP, 0);
            const gh = Math.max(cell.h - GAP, 0);
            const cx = gx + gw / 2;
            const cy = gy + gh / 2;
            const pct = ((cell.value / total) * 100).toFixed(0);
            const amt = (allRetraits ? '− ' : '') + fmtAmount(cell.value);

            const isHovered = hoveredIdx === i;

            /* Taille de police adaptée à la largeur disponible */
            const fsAmt  = Math.min(15, Math.max(10, gw / 7.5));
            const fsName = Math.min(12, Math.max(8,  gw / 9.5));
            const fsPct  = Math.min(11, Math.max(7,  gw / 11));

            const lineH = 15;

            /* Seuils d'affichage */
            const canShowAmt  = gw > 36 && gh > 20;

            /* Mode "paysage" : cellule plus large que haute */
            const isLandscape = gw > gh;

            /* Texte combiné "Nom — X %" : utilisé en paysage seulement s'il tient sur 1 ligne */
            const combinedText   = `${cell.name} — ${pct} %`;
            const combinedCharW  = fsName * 0.58;
            const combinedFits   = isLandscape && (combinedText.length * combinedCharW) <= (gw - 10);

            /* Word-wrap du nom seul (mode portrait ou paysage sans place pour le combiné) */
            const nameLines  = (gw > 40 && gh > 30)
              ? wrapText(cell.name, gw - 10, fsName)
              : [];
            const canShowName = nameLines.length > 0;

            /* Pourcentage séparé : s'assurer que la ligne % rentre dans le clipPath (PAD=4 de chaque côté) */
            const CLIP_PAD = 4;
            const textHeightSoFar = (canShowAmt ? lineH : 0) + (canShowName ? nameLines.length * lineH : 0);
            const canShowPct = !combinedFits && gw > 44 && (gh - CLIP_PAD * 2) >= textHeightSoFar + lineH;

            /* Pré-calcul des positions Y */
            const textItems = [];
            {
              const slots = [];
              if (canShowAmt) slots.push({ type: 'amt', h: lineH + 2 });
              if (combinedFits) {
                slots.push({ type: 'combined', text: combinedText, h: lineH });
              } else {
                if (canShowName) nameLines.forEach((l, li) => slots.push({ type: 'name', li, text: l, h: lineH }));
                if (canShowPct)  slots.push({ type: 'pct', h: lineH });
              }

              const totalH = slots.reduce((s, sl) => s + sl.h, 0);
              let y = cy - totalH / 2 + lineH / 2;

              for (const sl of slots) {
                if (sl.type === 'amt')      textItems.push({ key: 'amt',       text: amt,            fs: fsAmt,  fw: '700', op: 1,    y });
                if (sl.type === 'combined') textItems.push({ key: 'combined',  text: sl.text,        fs: fsName, fw: '500', op: 0.92, y });
                if (sl.type === 'name')     textItems.push({ key: `n${sl.li}`, text: sl.text,        fs: fsName, fw: '500', op: 0.92, y });
                if (sl.type === 'pct')      textItems.push({ key: 'pct',       text: pct + ' %',     fs: fsPct,  fw: '400', op: 0.75, y });
                y += sl.h;
              }
            }

            return (
              <g key={i} style={{ cursor: 'pointer' }}
                onMouseMove={e => handleMouseMove(e, { ...cell, pct, amt }, i)}
              >
                {/* Cellule colorée */}
                <rect x={gx} y={gy} width={gw} height={gh}
                  rx="5" fill={cell.color}
                  opacity={hoveredIdx !== null && !isHovered ? 0.45 : 0.9}
                  style={{ transition: 'opacity .15s' }}
                />
                {/* Dégradé sombre */}
                <rect x={gx} y={gy} width={gw} height={gh}
                  rx="5" fill="url(#dt-shadow)" opacity="0.35" />
                {/* Bordure lumineuse au hover */}
                {isHovered && (
                  <rect x={gx} y={gy} width={gw} height={gh}
                    rx="5" fill="none"
                    stroke="rgba(255,255,255,0.55)" strokeWidth="1.5" />
                )}
                {/* Labels */}
                <g clipPath={`url(#clip-${i})`}>
                  {textItems.map(l => (
                    <text key={l.key} x={cx} y={l.y}
                      textAnchor="middle" dominantBaseline="middle"
                      fill="white"
                      fillOpacity={hoveredIdx !== null && !isHovered ? 0.3 : l.op}
                      fontSize={l.fs} fontWeight={l.fw}
                      fontFamily="system-ui,-apple-system,sans-serif"
                      filter="url(#dt-txt-shadow)"
                      style={{ transition: 'fill-opacity .15s' }}>
                      {l.text}
                    </text>
                  ))}
                </g>
              </g>
            );
          })}
        </svg>

        {/* ── Tooltip ── */}
        {tooltip && tipStyle && (
          <div className="dist-tooltip" style={{ left: tipStyle.left, top: tipStyle.top }}>
            <div className="dist-tooltip-dot" style={{ background: tooltip.cell.color }} />
            <div>
              <div className="dist-tooltip-amt">{tooltip.cell.amt}</div>
              <div className="dist-tooltip-name">{tooltip.cell.name}</div>
              <div className="dist-tooltip-pct">{tooltip.cell.pct} %</div>
            </div>
          </div>
        )}
      </div>
    </div>
  );
}
