"use client";

import { useMemo, useRef, useState, type MouseEvent as ReactMouseEvent } from "react";
import type { ReportChart, ReportChartSeriesPoint } from "@/lib/reports/contracts";
import { formatValueByType } from "@/lib/reports/utils";

type ReportChartsProps = {
  charts: ReportChart[];
  comparisonCharts?: ReportChart[] | null;
};

type TooltipState = {
  label: string;
  value: string;
  comparisonValue?: string;
  x: number;
  y: number;
};

const CHART_COLORS = ["#3b82f6", "#22c55e", "#f59e0b", "#6366f1", "#8b5cf6", "#94a3b8"];

function getFormatType(chart: ReportChart) {
  if (chart.format === "currency") return "currency";
  if (chart.format === "percent") return "percent";
  return "number";
}

function formatChartValue(chart: ReportChart, value: number) {
  return formatValueByType(value, getFormatType(chart));
}

function getSeriesKey(chartId: string, label: string, index: number, suffix = "") {
  return `${chartId}-${index}-${label}${suffix}`;
}

function getTooltipPosition(event: ReactMouseEvent<Element>, container: HTMLDivElement | null) {
  if (!container) {
    return { x: 16, y: 16 };
  }

  const rect = container.getBoundingClientRect();
  const rawX = event.clientX - rect.left + 14;
  const rawY = event.clientY - rect.top - 14;
  const tooltipWidth = 220;
  const tooltipHeight = 88;

  return {
    x: Math.max(12, Math.min(rawX, rect.width - tooltipWidth - 12)),
    y: Math.max(12, Math.min(rawY, rect.height - tooltipHeight - 12)),
  };
}

function getSeriesMax(points: ReportChartSeriesPoint[], comparisonSeries?: ReportChartSeriesPoint[]) {
  return Math.max(
    1,
    ...points.map((point) => Number(point.value) || 0),
    ...(comparisonSeries ?? []).map((point) => Number(point.value) || 0)
  );
}

function getTicks(max: number) {
  const steps = 4;
  return Array.from({ length: steps + 1 }, (_, index) => {
    const value = (max / steps) * index;
    return {
      value,
      label: max >= 1000 ? `${Math.round(value / 1000)}k` : `${Math.round(value)}`,
    };
  }).reverse();
}

function getComparisonSeries(chart: ReportChart, comparisonChart?: ReportChart | null) {
  if (!comparisonChart) return null;
  return chart.series.map((point, index) => ({
    label: point.label,
    value: comparisonChart.series[index]?.value ?? 0,
  }));
}

function formatAxisLabel(value: number) {
  const absolute = Math.abs(value);
  if (absolute >= 1000) {
    const scaled = value / 1000;
    const rounded = Number.isInteger(scaled) ? scaled.toFixed(0) : scaled.toFixed(1);
    return `${rounded}k`;
  }
  return `${Math.round(value)}`;
}

function getLineRange(points: ReportChartSeriesPoint[], comparisonSeries?: ReportChartSeriesPoint[]) {
  const values = [
    ...points.map((point) => Number(point.value) || 0),
    ...(comparisonSeries ?? []).map((point) => Number(point.value) || 0),
  ];

  const min = Math.min(0, ...values);
  const max = Math.max(0, ...values);

  if (min === max) {
    return { min, max: max === 0 ? 1 : max };
  }

  return { min, max };
}

function getLineTicks(min: number, max: number) {
  const steps = 4;
  const range = max - min || 1;
  return Array.from({ length: steps + 1 }, (_, index) => {
    const value = max - (range / steps) * index;
    return {
      value,
      label: formatAxisLabel(value),
    };
  });
}

function projectLineY(value: number, min: number, max: number, top: number, height: number) {
  const range = max - min || 1;
  return top + height - ((value - min) / range) * height;
}

function getLinePath(points: Array<{ x: number; y: number }>) {
  if (points.length === 0) return "";
  return points.map((point, index) => `${index === 0 ? "M" : "L"} ${point.x} ${point.y}`).join(" ");
}

function getAreaPath(points: Array<{ x: number; y: number }>, baselineY: number) {
  if (points.length === 0) return "";
  return `${getLinePath(points)} L ${points[points.length - 1].x} ${baselineY} L ${points[0].x} ${baselineY} Z`;
}

function ChartTooltip({ tooltip }: { tooltip: TooltipState | null }) {
  if (!tooltip) return null;
  return (
    <div
      className="pointer-events-none absolute z-10 min-w-[150px] max-w-[220px] rounded-xl border border-[rgba(148,163,184,0.18)] bg-white/96 px-3 py-2 shadow-[0_14px_30px_rgba(15,23,42,0.12)] backdrop-blur"
      style={{ left: tooltip.x, top: tooltip.y }}
    >
      <div className="text-[11px] font-semibold uppercase tracking-[0.08em] text-[var(--ks-color-text-soft)]">
        {tooltip.label}
      </div>
      <div className="mt-1 text-sm font-semibold text-[var(--ks-color-text-primary)]">{tooltip.value}</div>
      {tooltip.comparisonValue ? (
        <div className="mt-1 text-xs text-[var(--ks-color-text-muted)]">Período anterior: {tooltip.comparisonValue}</div>
      ) : null}
    </div>
  );
}

function Legend({ items }: { items: Array<{ label: string; color: string; dashed?: boolean }> }) {
  return (
    <div className="flex flex-wrap items-center gap-4">
      {items.map((item) => (
        <div key={`${item.label}-${item.color}`} className="flex items-center gap-2 text-xs text-[var(--ks-color-text-muted)]">
          <span
            className={`block h-2.5 w-2.5 rounded-full ${item.dashed ? "border border-dashed bg-white" : ""}`}
            style={{
              backgroundColor: item.dashed ? "#ffffff" : item.color,
              borderColor: item.color,
            }}
          />
          <span>{item.label}</span>
        </div>
      ))}
    </div>
  );
}

function LineLikeChart({ chart, comparisonChart }: { chart: ReportChart; comparisonChart?: ReportChart | null }) {
  const [tooltip, setTooltip] = useState<TooltipState | null>(null);
  const chartRef = useRef<HTMLDivElement | null>(null);
  const width = 680;
  const height = 224;
  const padding = { top: 14, right: 14, bottom: 34, left: 46 };
  const comparisonSeries = useMemo(() => getComparisonSeries(chart, comparisonChart), [chart, comparisonChart]);
  const { min, max } = getLineRange(chart.series, comparisonSeries ?? undefined);
  const ticks = getLineTicks(min, max);
  const innerWidth = width - padding.left - padding.right;
  const innerHeight = height - padding.top - padding.bottom;

  const linePoints = chart.series.map((point, index) => {
    const x = padding.left + (chart.series.length === 1 ? innerWidth / 2 : (innerWidth / Math.max(1, chart.series.length - 1)) * index);
    const y = projectLineY(point.value, min, max, padding.top, innerHeight);
    return { x, y, point };
  });

  const comparisonPoints = (comparisonSeries ?? []).map((point, index) => {
    const x = padding.left + (comparisonSeries?.length === 1 ? innerWidth / 2 : (innerWidth / Math.max(1, (comparisonSeries?.length ?? 1) - 1)) * index);
    const y = projectLineY(point.value, min, max, padding.top, innerHeight);
    return { x, y, point };
  });

  const baselineY = projectLineY(0, min, max, padding.top, innerHeight);

  return (
    <div ref={chartRef} className="relative">
      <ChartTooltip tooltip={tooltip} />
      <svg viewBox={`0 0 ${width} ${height}`} className="h-[224px] w-full overflow-visible">
        <defs>
          <linearGradient id={`${chart.id}-fill`} x1="0" x2="0" y1="0" y2="1">
            <stop offset="0%" stopColor="#4f46e5" stopOpacity="0.18" />
            <stop offset="100%" stopColor="#4f46e5" stopOpacity="0.02" />
          </linearGradient>
        </defs>

        {ticks.map((tick) => {
          const y = projectLineY(tick.value, min, max, padding.top, innerHeight);
          return (
            <g key={`${chart.id}-tick-${tick.value}`}>
              <line x1={padding.left} x2={width - padding.right} y1={y} y2={y} stroke="#e2e8f0" strokeWidth="1" />
              <text x={padding.left - 10} y={y + 4} textAnchor="end" fontSize="11" fill="#94a3b8">
                {tick.label}
              </text>
            </g>
          );
        })}

        <line
          x1={padding.left}
          x2={width - padding.right}
          y1={baselineY}
          y2={baselineY}
          stroke="#cbd5e1"
          strokeWidth="1.2"
        />

        {comparisonPoints.length > 0 ? (
          <path
            d={getLinePath(comparisonPoints)}
            fill="none"
            stroke="#94a3b8"
            strokeWidth="2"
            strokeDasharray="6 6"
          />
        ) : null}

        <path d={getAreaPath(linePoints, baselineY)} fill={`url(#${chart.id}-fill)`} />
        <path d={getLinePath(linePoints)} fill="none" stroke="#4f46e5" strokeWidth="3" />

        {linePoints.map((item, index) => (
          <g key={getSeriesKey(chart.id, item.point.label, index, "-point")}>
            <line x1={item.x} x2={item.x} y1={padding.top} y2={height - padding.bottom} stroke="transparent" strokeWidth="22" />
            <circle
              cx={item.x}
              cy={item.y}
              r="4.5"
              fill="#ffffff"
              stroke="#4f46e5"
              strokeWidth="3"
              onMouseEnter={(event) =>
                setTooltip({
                  label: item.point.label,
                  value: formatChartValue(chart, item.point.value),
                  comparisonValue:
                    comparisonSeries && comparisonSeries[index]
                      ? formatChartValue(chart, comparisonSeries[index].value)
                      : undefined,
                  ...getTooltipPosition(event, chartRef.current),
                })
              }
              onMouseMove={(event) =>
                setTooltip((current) =>
                  current
                    ? {
                        ...current,
                        ...getTooltipPosition(event, chartRef.current),
                      }
                    : current
                )
              }
              onMouseLeave={() => setTooltip(null)}
            />
            <text x={item.x} y={height - padding.bottom + 18} textAnchor="middle" fontSize="11" fill="#64748b">
              {item.point.label}
            </text>
          </g>
        ))}
      </svg>
    </div>
  );
}

function ColumnChart({ chart }: { chart: ReportChart }) {
  const [tooltip, setTooltip] = useState<TooltipState | null>(null);
  const chartRef = useRef<HTMLDivElement | null>(null);
  const width = 680;
  const height = 224;
  const padding = { top: 14, right: 14, bottom: 34, left: 46 };
  const max = getSeriesMax(chart.series);
  const ticks = getTicks(max);
  const innerWidth = width - padding.left - padding.right;
  const innerHeight = height - padding.top - padding.bottom;
  const slotWidth = innerWidth / Math.max(1, chart.series.length);

  return (
    <div ref={chartRef} className="relative">
      <ChartTooltip tooltip={tooltip} />
      <svg viewBox={`0 0 ${width} ${height}`} className="h-[224px] w-full overflow-visible">
        {ticks.map((tick, index) => {
          const y = padding.top + (innerHeight / Math.max(1, ticks.length - 1)) * index;
          return (
            <g key={`${chart.id}-tick-${tick.value}`}>
              <line x1={padding.left} x2={width - padding.right} y1={y} y2={y} stroke="#e2e8f0" strokeWidth="1" />
              <text x={padding.left - 10} y={y + 4} textAnchor="end" fontSize="11" fill="#94a3b8">
                {tick.label}
              </text>
            </g>
          );
        })}

        <line
          x1={padding.left}
          x2={width - padding.right}
          y1={height - padding.bottom}
          y2={height - padding.bottom}
          stroke="#cbd5e1"
          strokeWidth="1.2"
        />

        {chart.series.map((point, index) => {
          const barWidth = Math.max(18, slotWidth * 0.56);
          const barHeight = (point.value / max) * innerHeight;
          const x = padding.left + slotWidth * index + (slotWidth - barWidth) / 2;
          const y = height - padding.bottom - barHeight;
          return (
            <g key={getSeriesKey(chart.id, point.label, index, "-bar")}>
              <rect
                x={x}
                y={y}
                width={barWidth}
                height={barHeight}
                rx="6"
                fill="#22c55e"
                onMouseEnter={(event) =>
                  setTooltip({
                    label: point.label,
                    value: formatChartValue(chart, point.value),
                    ...getTooltipPosition(event, chartRef.current),
                  })
                }
                onMouseMove={(event) =>
                  setTooltip((current) =>
                    current
                      ? {
                          ...current,
                          ...getTooltipPosition(event, chartRef.current),
                        }
                      : current
                  )
                }
                onMouseLeave={() => setTooltip(null)}
              />
              <text x={x + barWidth / 2} y={height - padding.bottom + 18} textAnchor="middle" fontSize="11" fill="#64748b">
                {point.label}
              </text>
            </g>
          );
        })}
      </svg>
    </div>
  );
}

function DonutChart({ chart }: { chart: ReportChart }) {
  const [tooltip, setTooltip] = useState<TooltipState | null>(null);
  const chartRef = useRef<HTMLDivElement | null>(null);
  const total = chart.series.reduce((sum, point) => sum + point.value, 0) || 1;
  const circumference = 2 * Math.PI * 58;
  const segments = chart.series.map((point, index) => {
    const strokeLength = (point.value / total) * circumference;
    const previousLength = chart.series
      .slice(0, index)
      .reduce((sum, current) => sum + (current.value / total) * circumference, 0);
    return {
      point,
      index,
      strokeLength,
      strokeDashoffset: -previousLength,
    };
  });

  return (
    <div ref={chartRef} className="relative grid gap-4 lg:grid-cols-[176px_minmax(0,1fr)] lg:items-center">
      <ChartTooltip tooltip={tooltip} />
      <div className="mx-auto flex h-[176px] w-[176px] items-center justify-center">
        <svg viewBox="0 0 160 160" className="h-[176px] w-[176px]">
          <circle cx="80" cy="80" r="58" fill="transparent" stroke="#e2e8f0" strokeWidth="18" />
          {segments.map(({ point, index, strokeLength, strokeDashoffset }) => (
              <circle
                key={getSeriesKey(chart.id, point.label, index, "-donut")}
                cx="80"
                cy="80"
                r="58"
                fill="transparent"
                stroke={CHART_COLORS[index % CHART_COLORS.length]}
                strokeWidth="18"
                strokeDasharray={`${strokeLength} ${circumference}`}
                strokeDashoffset={strokeDashoffset}
                strokeLinecap="butt"
                transform="rotate(-90 80 80)"
                onMouseEnter={(event) =>
                  setTooltip({
                    label: point.label,
                    value: `${formatChartValue(chart, point.value)} (${((point.value / total) * 100).toFixed(1)}%)`,
                    ...getTooltipPosition(event, chartRef.current),
                  })
                }
                onMouseMove={(event) =>
                  setTooltip((current) =>
                    current
                      ? {
                          ...current,
                          ...getTooltipPosition(event, chartRef.current),
                        }
                      : current
                  )
                }
                onMouseLeave={() => setTooltip(null)}
              />
            ))}
          <text x="80" y="74" textAnchor="middle" fontSize="12" fill="#64748b">
            Total
          </text>
          <text x="80" y="94" textAnchor="middle" fontSize="16" fontWeight="700" fill="#0f172a">
            {formatChartValue(chart, total)}
          </text>
        </svg>
      </div>

      <div className="space-y-2">
        {chart.series.map((point, index) => {
          const share = (point.value / total) * 100;
          return (
            <div
              key={getSeriesKey(chart.id, point.label, index, "-legend")}
              className="grid grid-cols-[12px_minmax(0,1fr)_64px] items-center gap-3 rounded-xl border border-gray-100 px-3 py-2"
            >
              <span className="h-2.5 w-2.5 rounded-full" style={{ backgroundColor: CHART_COLORS[index % CHART_COLORS.length] }} />
              <span className="truncate text-sm text-[var(--ks-color-text-muted)]">{point.label}</span>
              <span className="text-right text-sm font-semibold text-[var(--ks-color-text-primary)]">
                {share.toFixed(1)}%
              </span>
            </div>
          );
        })}
      </div>
    </div>
  );
}

function RankingChart({ chart }: { chart: ReportChart }) {
  const max = getSeriesMax(chart.series);
  return (
    <div className="space-y-3">
      {chart.series.map((point, index) => (
        <div key={getSeriesKey(chart.id, point.label, index, "-ranking")} className="grid grid-cols-[28px_minmax(0,1fr)_110px] items-center gap-3">
          <div className="flex h-7 w-7 items-center justify-center rounded-full bg-[rgba(79,70,229,0.08)] text-xs font-semibold text-[#4338ca]">
            {index + 1}
          </div>
          <div className="min-w-0">
            <div className="mb-1.5 truncate text-sm text-[var(--ks-color-text-primary)]">{point.label}</div>
            <div className="h-2.5 rounded-full bg-[rgba(226,232,240,0.85)]">
              <div
                className="h-2.5 rounded-full bg-[linear-gradient(90deg,#4f46e5,#3b82f6)]"
                style={{ width: `${(point.value / max) * 100}%` }}
              />
            </div>
          </div>
          <div className="text-right text-sm font-semibold text-[var(--ks-color-text-primary)]">
            {formatChartValue(chart, point.value)}
          </div>
        </div>
      ))}
    </div>
  );
}

function CompareChart({ chart }: { chart: ReportChart }) {
  const max = getSeriesMax(chart.series);
  return (
    <div className="grid gap-3 md:grid-cols-2">
      {chart.series.map((point, index) => (
        <div
          key={getSeriesKey(chart.id, point.label, index, "-compare")}
          className="rounded-2xl border border-[rgba(226,232,240,0.85)] bg-[rgba(248,250,252,0.7)] p-4"
        >
          <div className="flex items-center justify-between gap-3">
            <span className="text-sm font-medium text-[var(--ks-color-text-muted)]">{point.label}</span>
            <span className="text-sm font-semibold text-[var(--ks-color-text-primary)]">
              {formatChartValue(chart, point.value)}
            </span>
          </div>
          <div className="mt-3 h-2.5 rounded-full bg-[rgba(226,232,240,0.85)]">
            <div
              className="h-2.5 rounded-full"
              style={{
                width: `${(point.value / max) * 100}%`,
                backgroundColor: CHART_COLORS[index % CHART_COLORS.length],
              }}
            />
          </div>
          {typeof point.secondaryValue === "number" ? (
            <div className="mt-2 text-xs text-[var(--ks-color-text-soft)]">
              Base de comparação: {formatChartValue(chart, point.secondaryValue)}
            </div>
          ) : null}
        </div>
      ))}
    </div>
  );
}

function ChartBody({ chart, comparisonChart }: { chart: ReportChart; comparisonChart?: ReportChart | null }) {
  if (chart.type === "donut") return <DonutChart chart={chart} />;
  if (chart.type === "ranking") return <RankingChart chart={chart} />;
  if (chart.type === "compare") return <CompareChart chart={chart} />;
  if (chart.type === "column" || chart.type === "bar") return <ColumnChart chart={chart} />;
  return <LineLikeChart chart={chart} comparisonChart={comparisonChart} />;
}

export function ReportCharts({ charts, comparisonCharts }: ReportChartsProps) {
  if (charts.length === 0) return null;

  const comparisonMap = new Map((comparisonCharts ?? []).map((chart) => [chart.id, chart]));

  return (
    <section className="grid grid-cols-1 gap-4 xl:grid-cols-3">
      {charts.map((chart) => {
        const comparisonChart = comparisonMap.get(chart.id);
        const legendItems =
          chart.type === "donut"
            ? chart.series.slice(0, 5).map((point, index) => ({
                label: point.label,
                color: CHART_COLORS[index % CHART_COLORS.length],
              }))
            : comparisonChart
              ? [
                  { label: "Período atual", color: "#4f46e5" },
                  { label: "Período anterior", color: "#94a3b8", dashed: true },
                ]
              : [{ label: "Série principal", color: chart.type === "column" || chart.type === "bar" ? "#22c55e" : "#4f46e5" }];

        return (
          <article
            key={chart.id}
            id={`report-chart-${chart.id}`}
            className="overflow-hidden rounded-2xl border border-gray-100 bg-white px-4 py-4 shadow-none"
          >
            <div className="mb-4 flex flex-wrap items-start justify-between gap-3">
              <div>
                <h3 className="text-[15px] font-semibold text-[var(--ks-color-text-primary)]">{chart.title}</h3>
                <p className="mt-1 text-xs text-[var(--ks-color-text-soft)]">{chart.series.length} pontos analisados</p>
              </div>
              <Legend items={legendItems} />
            </div>
            <ChartBody chart={chart} comparisonChart={comparisonChart} />
          </article>
        );
      })}
    </section>
  );
}
