'use client';

import { useRef, useEffect } from 'react';
import {
  ScatterChart,
  Scatter,
  XAxis,
  YAxis,
  CartesianGrid,
  Tooltip,
  ResponsiveContainer,
  ZAxis,
  Cell,
  LabelList,
  ReferenceLine,
  ReferenceArea,
} from 'recharts';
import type { ThemeScore } from '../types';
import { getDomainColor } from '../styles/report-theme';
import { translateThemeLabel } from '../i18n/contentTranslations';

interface ThemeMatrixProps {
  themes: ThemeScore[];
  locale?: string;
}

interface DataPoint {
  x: number;
  y: number;
  z: number;
  name: string;
  domain: string;
  color: string;
}

interface PlacedRect {
  x: number;
  y: number;
  w: number;
  h: number;
}

const CHART_H = 320;
const CHART_MARGIN = { top: 30, right: 35, left: 15, bottom: 10 };

export default function ThemeMatrix({ themes, locale = 'en' }: ThemeMatrixProps) {
  const containerRef = useRef<HTMLDivElement>(null);
  const chartWidthRef = useRef(800);

  // Set SVG overflow: visible so edge labels aren't clipped, and measure width
  useEffect(() => {
    const el = containerRef.current;
    if (!el) return;
    const svg = el.querySelector('svg');
    if (svg) svg.setAttribute('overflow', 'visible');
    chartWidthRef.current = el.clientWidth;
  });

  if (themes.length === 0) {
    return (
      <div className="flex items-center justify-center h-64 text-gray-400">
        No theme data
      </div>
    );
  }

  // Sort by importance (z = weight × count) so larger bubbles get label priority
  const data: DataPoint[] = themes
    .map(t => {
      const total = t.valence.positive + t.valence.negative + t.valence.neutral + t.valence.mixed;
      const sentimentRatio = total > 0 ? (t.valence.positive - t.valence.negative) / total * 100 : 0;
      return {
        x: t.count,
        y: Math.round(sentimentRatio),
        z: t.weight * t.count,
        name: translateThemeLabel(t.label, locale),
        domain: t.domain,
        color: getDomainColor(t.domain),
      };
    })
    .sort((a, b) => b.z - a.z);

  const axisLabels = locale === 'es'
    ? { frequency: 'Frecuencia', sentiment: 'Sentimiento Neto %' }
    : { frequency: 'Frequency', sentiment: 'Net Sentiment %' };

  // Bubble radius estimator (matches ZAxis range [100, 600])
  const zValues = data.map(d => d.z);
  const zExtent = [Math.min(...zValues), Math.max(...zValues)] as const;
  const estimateR = (z: number) => {
    const area = 100 + ((z - zExtent[0]) / (zExtent[1] - zExtent[0] || 1)) * 500;
    return Math.sqrt(area / Math.PI);
  };

  // Greedy collision-avoidance label placement.
  // Mutable array reset each render — tracks placed label bounding boxes.
  const placedRects: PlacedRect[] = [];
  const CHAR_W = 5.5;
  const LABEL_H = 13;
  const GAP = 5;

  // eslint-disable-next-line @typescript-eslint/no-explicit-any
  const renderLabel = (props: any) => {
    const { x, y, value, index } = props;
    if (index === undefined || !value) return null;

    const point = data[index]!;
    const r = estimateR(point.z);
    const labelW = value.length * CHAR_W;

    // 4 candidate positions: above, right, left, below
    const candidates = [
      { ox: 0, oy: -(r + GAP), anchor: 'middle' as const },
      { ox: r + GAP + 2, oy: 3, anchor: 'start' as const },
      { ox: -(r + GAP + 2), oy: 3, anchor: 'end' as const },
      { ox: 0, oy: r + GAP + LABEL_H, anchor: 'middle' as const },
    ];

    let best = candidates[0]!;
    let bestOverlap = Infinity;

    for (const cand of candidates) {
      const lx = cand.anchor === 'middle' ? (x + cand.ox - labelW / 2)
               : cand.anchor === 'start' ? (x + cand.ox)
               : (x + cand.ox - labelW);
      const ly = (y + cand.oy) - LABEL_H;

      let overlap = 0;

      // Boundary penalty — heavily penalize positions outside the chart area
      if (ly < 2 || (ly + LABEL_H) > CHART_H - 2) overlap += 50000;
      if (lx < 2 || (lx + labelW) > chartWidthRef.current - 2) overlap += 50000;

      for (const rect of placedRects) {
        const ox = Math.max(0, Math.min(lx + labelW, rect.x + rect.w) - Math.max(lx, rect.x));
        const oy = Math.max(0, Math.min(ly + LABEL_H, rect.y + rect.h) - Math.max(ly, rect.y));
        overlap += ox * oy;
      }

      if (overlap < bestOverlap) {
        bestOverlap = overlap;
        best = cand;
      }
      if (overlap === 0) break;
    }

    const finalX = x + best.ox;
    const finalY = y + best.oy;
    const lx = best.anchor === 'middle' ? (finalX - labelW / 2)
             : best.anchor === 'start' ? finalX
             : (finalX - labelW);
    placedRects.push({ x: lx, y: finalY - LABEL_H, w: labelW, h: LABEL_H });

    return (
      <text x={finalX} y={finalY} textAnchor={best.anchor} fill="#475569" fontSize={10} fontWeight={500}>
        {value}
      </text>
    );
  };

  // Compute Y domain with padding for gradient zones
  const yValues = data.map(d => d.y);
  const yMin = Math.min(-20, ...yValues) - 10;
  const yMax = Math.max(20, ...yValues) + 10;

  return (
    <div ref={containerRef}>
    <ResponsiveContainer width="100%" height={CHART_H}>
      <ScatterChart margin={CHART_MARGIN}>
        {/* Gradient background zones */}
        <defs>
          <linearGradient id="positiveZone" x1="0" y1="1" x2="0" y2="0">
            <stop offset="0%" stopColor="#22c55e" stopOpacity={0.02} />
            <stop offset="100%" stopColor="#22c55e" stopOpacity={0.08} />
          </linearGradient>
          <linearGradient id="negativeZone" x1="0" y1="0" x2="0" y2="1">
            <stop offset="0%" stopColor="#ef4444" stopOpacity={0.02} />
            <stop offset="100%" stopColor="#ef4444" stopOpacity={0.08} />
          </linearGradient>
        </defs>
        <ReferenceArea y1={0} y2={yMax} fill="url(#positiveZone)" strokeOpacity={0} />
        <ReferenceArea y1={yMin} y2={0} fill="url(#negativeZone)" strokeOpacity={0} />
        <CartesianGrid strokeDasharray="3 3" stroke="#e5e7eb" />
        <XAxis
          type="number"
          dataKey="x"
          name="Frequency"
          tick={{ fill: '#6b7280', fontSize: 11 }}
          tickLine={false}
          axisLine={false}
          label={{ value: axisLabels.frequency, position: 'insideBottom', offset: -5, fill: '#9ca3af', fontSize: 12 }}
        />
        <YAxis
          type="number"
          dataKey="y"
          name="Sentiment"
          domain={[yMin, yMax]}
          tick={{ fill: '#6b7280', fontSize: 11 }}
          tickLine={false}
          axisLine={false}
          label={{ value: axisLabels.sentiment, angle: -90, position: 'insideLeft', fill: '#9ca3af', fontSize: 12 }}
        />
        <ReferenceLine y={0} stroke="#94a3b8" strokeWidth={1.5} strokeDasharray="" />
        <ZAxis type="number" dataKey="z" range={[100, 600]} />
        <Tooltip
          content={({ active, payload }) => {
            if (!active || !payload?.length) return null;
            // eslint-disable-next-line @typescript-eslint/no-explicit-any
            const point = (payload[0] as any)?.payload as DataPoint | undefined;
            if (!point) return null;
            return (
              <div style={{ background: 'white', border: '1px solid #e5e7eb', borderRadius: 8, padding: '8px 12px', boxShadow: '0 2px 8px rgba(0,0,0,0.08)' }}>
                <div style={{ fontWeight: 700, fontSize: 13, color: '#1E293B', marginBottom: 4 }}>{point.name}</div>
                <div style={{ fontSize: 12, color: '#6b7280' }}>
                  {locale === 'es' ? 'Menciones' : 'Mentions'}: <strong>{point.x}</strong>
                </div>
                <div style={{ fontSize: 12, color: '#6b7280' }}>
                  {locale === 'es' ? 'Sentimiento Neto' : 'Net Sentiment'}: <strong>{point.y}%</strong>
                </div>
              </div>
            );
          }}
        />
        <Scatter data={data}>
          {data.map((entry, i) => (
            <Cell key={i} fill={entry.color} />
          ))}
          <LabelList dataKey="name" content={renderLabel} />
        </Scatter>
      </ScatterChart>
    </ResponsiveContainer>
    </div>
  );
}
