import { useCallback, useMemo, useState } from 'react';
import {
  ChartRoot,
  XAxis,
  YAxis,
  Grid,
  TooltipHost,
  Legend,
  FloatingTooltip,
  bandScale,
  linearScale,
  buildLinePath,
  closeAreaPath,
} from './native';
import {
  CHART_DEFAULT_CATEGORY_COUNT,
  CHART_DEFAULT_Y_AXIS_TICK_COUNT,
  buildNumericYDomainZeroOrDataMin,
  buildStackedPositiveYDomain,
  chartMockCategoryDateLabel,
  normalizeDataColorToken,
  getDefaultDataColorToken,
  snapNumericAxisToIntegerUniformTicks,
} from './chart-common';
import ChartTooltip from './ChartTooltip';
import { tokenNameToCssVar, resolveCssNumericVar } from '../utils/token-resolver.js';
import {
  CHART_DATA_LABEL_POINT_RADIUS,
  CHART_SERIES_LINE_STROKE_WIDTH,
} from './chart-line-primitives';

export { CHART_DATA_COLOR_SLOTS } from './chart-common';

const FALLBACK_FILL = '#98A2B3';

const DEFAULT_DATA = Array.from({ length: CHART_DEFAULT_CATEGORY_COUNT }, (_, idx) => ({
  name: chartMockCategoryDateLabel(idx),
  v1: 16 + idx * 2 + (idx % 4),
  v2: 12 + idx * 2 + ((idx + 2) % 3),
}));

const DEFAULT_SERIES = [
  { dataKey: 'v1', colorToken: 'data-0', name: '序列 A' },
  { dataKey: 'v2', colorToken: 'data-4', name: '序列 B' },
];

const AREA_GRADIENT_BOTTOM_OPACITY = 0;
const AREA_GRADIENT_TOP_OPACITY_DEFAULT = 0.18;
const AREA_STACK_FILL_OPACITY_DEFAULT = 0.38;

function pickCurveType(c) {
  const raw = c?.curveType ?? c?.curve;
  return ['linear', 'monotone', 'step'].includes(raw) ? raw : 'linear';
}

function mergeConfig(c) {
  const defaults = {
    stack: false,
    grid: true,
    showLegend: true,
    showXAxis: true,
    showYAxis: true,
    showLabel: false,
    showValueLabel: false,
    curveType: 'linear',
    legendPosition: 'bottom',
    legendShape: 'line',
    yAxisTickCount: CHART_DEFAULT_Y_AXIS_TICK_COUNT,
    height: 340,
    margin: { top: 20, right: 20, left: 10, bottom: 10 },
  };
  if (!c || typeof c !== 'object') return { ...defaults };
  const merged = { ...defaults, ...c };
  merged.stack = !!merged.stack;
  merged.curveType = pickCurveType(merged);
  merged.grid =
    typeof merged.grid === 'boolean'
      ? merged.grid
      : typeof merged.showGrid === 'boolean'
        ? merged.showGrid
        : defaults.grid;
  merged.showLabel = !!(merged.showLabel ?? merged.showValueLabel);
  merged.showValueLabel = merged.showLabel;
  merged.height = Number(merged.height ?? defaults.height) || defaults.height;
  merged.margin = { ...defaults.margin, ...(merged.margin || {}) };
  return merged;
}

/** 取色：优先 token CSS 变量，外部 fallback hex */
function resolveSeriesColor(colorToken) {
  const v = tokenNameToCssVar(colorToken);
  if (v && v.startsWith('--')) return `var(${v}, ${FALLBACK_FILL})`;
  return FALLBACK_FILL;
}

/**
 * 面积图（native 实现，外塔 API 与原 SmartAreaChart 一致）
 *
 * P2.1 覆盖：单轴 / 网格虚线 / 多系列 / linear|monotone|step / 渐变填充 /
 *          堆叠（stack）/ Legend 4 向 / hover 游标 + Tooltip 跟随鼠标
 */
export default function SmartAreaChart({ spec }) {
  const { data, series, config: rawConfig } = spec || {};
  const config = mergeConfig(rawConfig);
  const resolveRoot = config.resolveRoot;
  const resolveOpts = useMemo(() => (resolveRoot ? { root: resolveRoot } : {}), [resolveRoot]);
  const {
    stack,
    grid,
    showLegend,
    showXAxis,
    showYAxis,
    showLabel,
    curveType,
    legendPosition,
    legendShape,
    yAxisTickCount,
    height,
    margin: marginCfg,
  } = config;

  const seriesNormalized = useMemo(() => {
    const list = Array.isArray(series) && series.length > 0 ? series : DEFAULT_SERIES;
    return list.map((s, idx) => ({
      ...s,
      dataKey: s.dataKey,
      name: s.name ?? s.dataKey,
      colorToken: normalizeDataColorToken(s.colorToken || getDefaultDataColorToken(idx)),
    }));
  }, [series]);

  const seriesColors = useMemo(
    () => seriesNormalized.map((s) => resolveSeriesColor(s.colorToken)),
    [seriesNormalized],
  );

  const fillOpacityMulti = useMemo(() => {
    const v = resolveCssNumericVar('chart-area-fill-opacity-multi', resolveOpts);
    return Math.min(1, Math.max(0, Number.isFinite(v) ? v : AREA_GRADIENT_TOP_OPACITY_DEFAULT));
  }, [resolveOpts]);
  const fillOpacityStack = useMemo(() => {
    const v = resolveCssNumericVar('chart-area-fill-opacity-stack', resolveOpts);
    return Math.min(1, Math.max(0.08, Number.isFinite(v) ? v : AREA_STACK_FILL_OPACITY_DEFAULT));
  }, [resolveOpts]);

  const chartData = Array.isArray(data) && data.length > 0 ? data : DEFAULT_DATA;
  const categories = chartData.map((row) => row.name);

  const yAxisTickCountResolved = Math.max(
    2,
    Number.isFinite(Number(yAxisTickCount)) ? Number(yAxisTickCount) : CHART_DEFAULT_Y_AXIS_TICK_COUNT,
  );

  // ── Y 轴 domain（堆叠 / 非堆叠两种）
  const yDomain = useMemo(() => {
    const keys = seriesNormalized.map((s) => s.dataKey);
    if (stack) return buildStackedPositiveYDomain(chartData, keys) || [0, 1];
    return buildNumericYDomainZeroOrDataMin(chartData, keys) || [0, 1];
  }, [stack, chartData, seriesNormalized]);

  const yAxisUi = useMemo(
    () => snapNumericAxisToIntegerUniformTicks(yDomain, yAxisTickCountResolved),
    [yDomain, yAxisTickCountResolved],
  );

  // ── margin（包含 legend 占位）
  const margin = useMemo(() => {
    const m = {
      top: Math.max(Number(marginCfg?.top) || 0, 16),
      right: Math.max(Number(marginCfg?.right) || 0, 24),
      bottom: Math.max(Number(marginCfg?.bottom) || 0, 8),
      left: Math.max(Number(marginCfg?.left) || 0, 8),
    };
    if (showXAxis) m.bottom += 24;
    if (showYAxis) m.left += 36;
    if (showLegend) {
      if (legendPosition === 'top') m.top += 28;
      else if (legendPosition === 'bottom') m.bottom += 28;
      else if (legendPosition === 'left') m.left += 96;
      else if (legendPosition === 'right') m.right += 96;
    }
    return m;
  }, [marginCfg, showXAxis, showYAxis, showLegend, legendPosition]);

  const [active, setActive] = useState(null);
  const handleActive = useCallback((info) => setActive(info), []);

  // 堆叠态下计算每行的累计值（按 series 顺序自下往上叠）
  const stackedRows = useMemo(() => {
    if (!stack) return null;
    return chartData.map((row) => {
      const acc = [];
      let total = 0;
      for (const s of seriesNormalized) {
        const v = Number(row[s.dataKey]);
        const safe = Number.isFinite(v) ? v : 0;
        acc.push({ low: total, high: total + safe, raw: safe });
        total += safe;
      }
      return acc;
    });
  }, [stack, chartData, seriesNormalized]);

  return (
    <div
      className="smart-area-chart"
      style={{ width: '100%', height, position: 'relative', background: 'var(--color-surface, #FFFFFF)' }}
    >
      <ChartRoot height={height} margin={margin}>
        {({ width, plot }) => {
          const xScale = bandScale(categories, [plot.x, plot.x + plot.w], { paddingOuter: 0.5, paddingInner: 1 });
          const yScale = linearScale(
            [yAxisUi?.domain?.[0] ?? yDomain[0], yAxisUi?.domain?.[1] ?? yDomain[1]],
            [plot.y + plot.h, plot.y],
          );
          const yTicksRaw = yAxisUi?.ticks || [yDomain[0], yDomain[1]];
          const baselineY = yScale(yDomain[0]);

          const xTicksObj = categories.map((k) => ({
            value: k,
            x: xScale.center(k) ?? 0,
            label: String(k),
          }));
          const yTicksObj = yTicksRaw.map((v) => ({
            value: v,
            y: yScale(v),
            label: String(v),
          }));

          // ── 系列点位
          const seriesPoints = seriesNormalized.map((s, sIdx) => {
            const pts = chartData
              .map((row, rIdx) => {
                const x = xScale.center(row.name);
                if (x == null) return null;
                if (stack) {
                  const stk = stackedRows?.[rIdx]?.[sIdx];
                  if (!stk) return null;
                  return {
                    x,
                    y: yScale(stk.high),
                    yLow: yScale(stk.low),
                    raw: stk.raw,
                  };
                }
                const v = Number(row[s.dataKey]);
                if (!Number.isFinite(v)) return null;
                return { x, y: yScale(v), yLow: baselineY, raw: v };
              })
              .filter(Boolean);
            return { ...s, pts };
          });

          // ── active 类目
          const activeKey = active?.key;
          const activeRow = activeKey != null ? chartData.find((r) => r.name === activeKey) : null;
          const activeX = activeKey != null ? xScale.center(activeKey) : null;

          return (
            <>
              <svg
                width={width}
                height={height}
                style={{ display: 'block', overflow: 'visible' }}
              >
                {/* 渐变定义（非堆叠态） */}
                {!stack && (
                  <defs>
                    {seriesNormalized.map((s, idx) => {
                      const safeKey = String(s.dataKey ?? `s${idx}`).replace(/[^a-zA-Z0-9_-]/g, '-');
                      const gradientId = `smart-area-fill-${idx}-${safeKey}`;
                      const color = seriesColors[idx];
                      return (
                        <linearGradient key={gradientId} id={gradientId} x1="0" y1="0" x2="0" y2="1">
                          <stop offset="0%" stopColor={color} stopOpacity={fillOpacityMulti} />
                          <stop offset="52%" stopColor={color} stopOpacity={fillOpacityMulti * 0.6} />
                          <stop offset="100%" stopColor={color} stopOpacity={AREA_GRADIENT_BOTTOM_OPACITY} />
                        </linearGradient>
                      );
                    })}
                  </defs>
                )}

                {grid && (
                  <Grid plot={plot} yTicks={yTicksObj} showHorizontal />
                )}
                {showXAxis && <XAxis plot={plot} ticks={xTicksObj} />}
                {showYAxis && <YAxis plot={plot} ticks={yTicksObj} />}

                {/* hover 游标 */}
                {activeX != null && (
                  <line
                    x1={activeX}
                    x2={activeX}
                    y1={plot.y}
                    y2={plot.y + plot.h}
                    stroke="var(--color-border-divider, #E5E6EB)"
                    strokeWidth={1}
                    strokeDasharray="3 3"
                    pointerEvents="none"
                  />
                )}

                {/* 面积 + 折线（堆叠态自下往上覆盖） */}
                {seriesPoints.map((s, i) => {
                  if (s.pts.length === 0) return null;
                  const color = seriesColors[i];
                  const linePath = buildLinePath(s.pts, curveType);
                  const safeKey = String(s.dataKey ?? `s${i}`).replace(/[^a-zA-Z0-9_-]/g, '-');
                  const gradientId = `smart-area-fill-${i}-${safeKey}`;

                  // 面积 path：堆叠态在 high → low 之间闭合；非堆叠 high → baseline
                  let areaD;
                  if (stack) {
                    const downPts = [...s.pts].reverse().map((p) => ({ x: p.x, y: p.yLow }));
                    const downPath = buildLinePath(downPts, curveType);
                    areaD = `${linePath} L${downPts[0].x.toFixed(2)},${downPts[0].y.toFixed(2)} ${downPath.replace(/^M/, 'L')} Z`;
                  } else {
                    areaD = closeAreaPath(linePath, s.pts, baselineY);
                  }

                  return (
                    <g key={s.dataKey}>
                      <path
                        d={areaD}
                        fill={stack ? color : `url(#${gradientId})`}
                        fillOpacity={stack ? fillOpacityStack : 1}
                        stroke="none"
                      />
                      {showLabel && s.pts.map((p, j) => (
                        <circle
                          key={`label-point-${j}`}
                          cx={p.x}
                          cy={p.y}
                          r={CHART_DATA_LABEL_POINT_RADIUS}
                          fill={color}
                          pointerEvents="none"
                        />
                      ))}
                      <path
                        d={linePath}
                        fill="none"
                        stroke={color}
                        strokeWidth={CHART_SERIES_LINE_STROKE_WIDTH}
                        strokeLinejoin="round"
                        strokeLinecap="round"
                      />
                      {/* hover 高亮点 */}
                      {activeKey != null && (() => {
                        const idx = chartData.findIndex((r) => r.name === activeKey);
                        if (idx < 0) return null;
                        const p = s.pts[idx];
                        if (!p) return null;
                        return (
                          <circle
                            cx={p.x}
                            cy={p.y}
                            r={4}
                            fill="#FFFFFF"
                            stroke={color}
                            strokeWidth={2}
                          />
                        );
                      })()}
                    </g>
                  );
                })}

                {/* 数据标签：按同类目做轻量避让，默认关闭，不参与坐标轴布局 */}
                {showLabel && (() => {
                  const minGap = 14;
                  const labels = seriesPoints.flatMap((s) =>
                    s.pts.map((p, pointIndex) => ({
                      key: `${s.dataKey}-${pointIndex}`,
                      x: p.x,
                      y: p.y - 8,
                      raw: p.raw,
                    })),
                  );
                  const byX = new Map();
                  labels.forEach((label) => {
                    const key = Math.round(label.x);
                    const group = byX.get(key) || [];
                    group.push(label);
                    byX.set(key, group);
                  });
                  const placed = [];
                  const labelTopBoundary = Math.max(8, plot.y - 8);
                  byX.forEach((group) => {
                    const sorted = [...group].sort((a, b) => a.y - b.y);
                    let prevY = -Infinity;
                    sorted.forEach((label) => {
                      const y = Math.max(label.y, prevY + minGap);
                      prevY = y;
                      placed.push({
                        ...label,
                        y: Math.min(Math.max(y, labelTopBoundary), plot.y + plot.h - 4),
                      });
                    });
                  });
                  return placed.map((label) => (
                    <text
                      key={label.key}
                      x={label.x}
                      y={label.y}
                      textAnchor="middle"
                      fontSize={11}
                      fill="var(--color-foreground-secondary, #475467)"
                      pointerEvents="none"
                    >
                      {String(label.raw)}
                    </text>
                  ));
                })()}

                {/* hover 探测层 */}
                <TooltipHost
                  plot={plot}
                  getCategoryAtX={(px) => xScale.invert(px)}
                  onActiveChange={handleActive}
                />
              </svg>

              {/* Legend */}
              {showLegend && (
                <div
                  style={{
                    position: 'absolute',
                    left: 0,
                    right: 0,
                    ...(legendPosition === 'top' ? { top: 0 } : {}),
                    ...(legendPosition === 'bottom' ? { bottom: 0 } : {}),
                    ...(legendPosition === 'left' ? { left: 0, top: '50%', transform: 'translateY(-50%)', right: 'auto', width: 96 } : {}),
                    ...(legendPosition === 'right' ? { right: 0, top: '50%', transform: 'translateY(-50%)', left: 'auto', width: 96 } : {}),
                    padding: '4px 8px',
                  }}
                >
                  <Legend
                    items={seriesNormalized.map((s, i) => ({ name: s.name, color: seriesColors[i] }))}
                    shape={legendShape === 'dot' ? 'dot' : 'line'}
                    position={legendPosition}
                  />
                </div>
              )}

              {/* Tooltip 浮层（HTML 层）：跟随鼠标，向右上展开；过 70% 翻到左侧 */}
              {activeRow && active && (
                <FloatingTooltip mouse={{ clientX: active.clientX, clientY: active.clientY }}>
                  <ChartTooltip
                    variant="chart"
                    label={String(activeRow.name)}
                    rows={seriesNormalized.map((s, i) => ({
                      name: s.name,
                      value: Number(activeRow[s.dataKey]),
                      color: seriesColors[i],
                      dataKey: s.dataKey,
                    }))}
                  />
                </FloatingTooltip>
              )}
            </>
          );
        }}
      </ChartRoot>
    </div>
  );
}
