/**
 * Dashboard charts — bar (تعداد بیماران) + line/area (میزان درآمد).
 *
 * The source (clinic-pro-tauri) draws these with @mui/x-charts. MUI is not used
 * in clinicpro, so they are reproduced with plain DOM + inline SVG, matching the
 * source visuals: bars #5559CE, dashed horizontal grid, y-axis ticks #858D9D,
 * x-axis labels #7E7E7E. The income line follows the ApexCharts «gradient line»
 * look instead — gradient stroke, glow, fading area and hover markers — drawn
 * from the theme tokens so it tracks light/dark mode.
 */
import React from 'react';

export interface ChartPoint {
  label: string;
  value: number;
}

/** ~5 rounded gridline ticks covering [0, max], top → bottom. Deduped so tiny
 *  integer ranges (e.g. max=1) never render repeated labels. */
function niceTicks(max: number, count = 4): number[] {
  const safeMax = max > 0 ? max : 1;
  const rawStep = safeMax / count;
  const mag = Math.pow(10, Math.floor(Math.log10(rawStep)));
  const norm = rawStep / mag;
  const niceNorm = norm <= 1 ? 1 : norm <= 2 ? 2 : norm <= 5 ? 5 : 10;
  const step = niceNorm * mag;
  const ticks: number[] = [];
  for (let i = count; i >= 0; i--) ticks.push(Math.round(step * i));
  // collapse duplicate rounded labels (keeps gridlines proportional via ticks[0])
  const deduped = ticks.filter((t, i) => i === 0 || t !== ticks[i - 1]);
  return deduped.length >= 2 ? deduped : [ticks[0], 0];
}

const faNum = new Intl.NumberFormat('fa-IR');

/** منحنی نرم از میان نقاط (کنترل‌پوینت وسط هر بازه — همان شکل قبلی خط). */
function smoothPath(pts: [number, number][]): string {
  return pts
    .map((p, i) => {
      if (i === 0) return `M${p[0]},${p[1]}`;
      const prev = pts[i - 1];
      const cx = (prev[0] + p[0]) / 2;
      return `C${cx},${prev[1]} ${cx},${p[1]} ${p[0]},${p[1]}`;
    })
    .join(' ');
}

/**
 * ادامهٔ فرضیِ سری برای ماه‌هایی که هنوز نرسیده‌اند: برازش خطی روی حداکثر ۶ نقطهٔ
 * آخر (روند اخیر، نه کل سال) و ادامه دادن همان شیب. خروجی هرگز منفی نمی‌شود.
 *
 * این یک عدد واقعی نیست — نمودار آن را نقطه‌چین و با برچسب «پیش‌بینی» نشان می‌دهد.
 */
function projectTrend(actual: number[], count: number): number[] {
  const window = actual.slice(-6);
  const n = window.length;
  const meanX = (n - 1) / 2;
  const meanY = window.reduce((s, v) => s + v, 0) / n;
  let num = 0;
  let den = 0;
  window.forEach((v, i) => {
    num += (i - meanX) * (v - meanY);
    den += (i - meanX) ** 2;
  });
  const slope = den === 0 ? 0 : num / den;
  const last = actual[actual.length - 1];
  return Array.from({ length: count }, (_, k) => Math.max(0, Math.round(last + slope * (k + 1))));
}

/**
 * Shared plot frame: left y-axis tick column + dashed gridlines + bottom x-axis
 * labels. `render(top, bottom)` receives the plot-area vertical bounds (px kept
 * implicit via fl/percentages) and returns the plot content.
 */
function ChartFrame({
  ticks,
  labels,
  yWidth,
  children,
}: {
  ticks: number[];
  labels: string[];
  yWidth: number;
  children: React.ReactNode;
}) {
  // NOTE: styles.css ships an unlayered legacy `.flex { align-items: center }`
  // which beats Tailwind's layered `items-*` utilities, collapsing the plot
  // column to zero height. Inline `alignItems` is the only reliable override.
  return (
    <div className="h-[300px] w-full flex flex-col px-[20px] pb-[12px]" style={{ alignItems: 'stretch' }}>
      <div className="flex-1 flex min-h-0" style={{ alignItems: 'stretch' }}>
        {/* y-axis ticks, aligned to gridlines */}
        <div
          className="flex flex-col justify-between text-[14px] font-normal text-[var(--text-2)] text-left pl-[4px] shrink-0"
          style={{ width: yWidth, alignItems: 'flex-start' }}
        >
          {ticks.map((t, i) => (
            <span key={i} className="leading-none -translate-y-1/2 first:translate-y-0 last:translate-y-0">
              {faNum.format(t)}
            </span>
          ))}
        </div>
        {/* plot area */}
        {/* overflow-hidden keeps a dense series (a 31-day month) inside the card */}
        <div className="relative flex-1 min-w-0 overflow-hidden">
          {ticks.map((_, i) => (
            <div
              key={i}
              className="absolute left-0 right-0 border-t border-dashed border-[var(--border)]"
              style={{ top: `${(i / (ticks.length - 1)) * 100}%` }}
            />
          ))}
          {children}
        </div>
      </div>
      {/* x-axis labels */}
      <div className="flex pt-[8px]" style={{ paddingRight: yWidth, alignItems: 'flex-start' }}>
        {labels.map((l, i) => (
          <span key={i} className="flex-1 min-w-0 overflow-hidden text-center text-[10px] font-normal text-[var(--text-2)] whitespace-nowrap">
            {l}
          </span>
        ))}
      </div>
    </div>
  );
}

/** Bar chart — thin #5559CE columns (source: BarPlot, categoryGapRatio 0.7). */
export function TauriBarChart({ data }: { data: ChartPoint[] }) {
  if (!data.length || !data.some((d) => d.value > 0)) {
    return <EmptyChart />;
  }
  const max = Math.max(...data.map((d) => d.value), 1);
  const ticks = niceTicks(max);
  const top = ticks[0] || 1;
  return (
    <ChartFrame ticks={ticks} labels={data.map((d) => d.label)} yWidth={42}>
      {/* `min-w-0` on every column is required: without it each column's
          intrinsic min-width is the bar's own width, so a 31-day month sums to
          more than the plot width and the whole row overflows out of the card.
          The bar is therefore a fraction of its column (which leaves the gap
          between bars) and only capped at the source's 24px. */}
      <div className="absolute inset-0 flex items-stretch" style={{ alignItems: 'stretch' }}>
        {data.map((d, i) => (
          <div key={i} className="flex-1 min-w-0 flex items-end justify-center" style={{ alignItems: 'flex-end' }}>
            <div
              title={faNum.format(d.value)}
              className="w-[60%] max-w-[24px] rounded-t-[3px] bg-[var(--primary)]"
              style={{
                height: `${(d.value / top) * 100}%`,
                minHeight: d.value > 0 ? 4 : 0,
                animation: `tdgrowcol .9s ${i * 0.06}s cubic-bezier(.22,.61,.36,1) both`,
              }}
            />
          </div>
        ))}
      </div>
      <style>{`@keyframes tdgrowcol{from{height:0}}`}</style>
    </ChartFrame>
  );
}

/**
 * Line + area chart in the ApexCharts «gradient line» style: a smooth curve whose
 * stroke runs through a horizontal gradient (--primary → --accent), a soft glow
 * beneath it, a fading area fill, and markers + tooltip that appear on hover.
 *
 * Still hand-drawn SVG — no charting dependency. The plot is scaled non-uniformly
 * (`preserveAspectRatio="none"`), so anything that must stay round (markers) or
 * readable (tooltip) lives in an HTML overlay positioned in percentages instead.
 */
export function TauriLineChart({ data, actualCount }: { data: ChartPoint[]; actualCount?: number }) {
  if (data.length < 2 || !data.some((d) => d.value > 0)) {
    return <EmptyChart />;
  }
  // ماه‌های نیامده صفر برمی‌گردند؛ رسم‌کردنشان یک خط صاف زشت تا انتهای سال می‌سازد.
  // به‌جای آن، از آخرین دادهٔ واقعی به بعد روند را ادامه می‌دهیم و نقطه‌چین می‌کشیم.
  const nActual = Math.min(actualCount ?? data.length, data.length);
  const hasForecast = nActual >= 2 && nActual < data.length;
  const values = hasForecast
    ? [...data.slice(0, nActual).map((d) => d.value), ...projectTrend(data.slice(0, nActual).map((d) => d.value), data.length - nActual)]
    : data.map((d) => d.value);

  const max = Math.max(...values, 1);
  const ticks = niceTicks(max);
  const top = ticks[0] || 1;

  // SVG plot: 0..100 in both axes, non-uniform scaling (path has no text).
  const W = 100;
  const H = 100;
  const stepX = data.length > 1 ? W / (data.length - 1) : W;
  const pts = values.map((v, i) => [i * stepX, H - (v / top) * H] as [number, number]);
  // خط پیش‌بینی از آخرین نقطهٔ واقعی شروع می‌شود تا وصله‌ی دو بخش دیده نشود.
  const solid = smoothPath(hasForecast ? pts.slice(0, nActual) : pts);
  const dashed = hasForecast ? smoothPath(pts.slice(nActual - 1)) : '';
  const areaPts = hasForecast ? pts.slice(0, nActual) : pts;
  const area = `${smoothPath(areaPts)} L${areaPts[areaPts.length - 1][0]},${H} L${areaPts[0][0]},${H} Z`;

  return (
    <ChartFrame ticks={ticks} labels={data.map((x) => x.label)} yWidth={64}>
      <svg
        className="absolute inset-0 h-full w-full overflow-visible"
        viewBox={`0 0 ${W} ${H}`}
        preserveAspectRatio="none"
      >
        <defs>
          {/* رنگِ خط در طول محور افقی از برند به اکسنت می‌رود (سبک دموی apex) */}
          <linearGradient id="tdIncomeStroke" x1="0" y1="0" x2="1" y2="0">
            <stop offset="0%" stopColor="var(--primary)" />
            <stop offset="55%" stopColor="var(--primary-600)" />
            <stop offset="100%" stopColor="var(--accent)" />
          </linearGradient>
          <linearGradient id="tdIncomeGrad" x1="0" y1="0" x2="0" y2="1">
            <stop offset="0%" stopColor="var(--primary)" stopOpacity={0.22} />
            <stop offset="100%" stopColor="var(--primary)" stopOpacity={0} />
          </linearGradient>
          <filter id="tdIncomeGlow" x="-20%" y="-40%" width="140%" height="200%">
            <feDropShadow dx="0" dy="4" stdDeviation="4" floodColor="var(--primary)" floodOpacity="0.28" />
          </filter>
        </defs>
        <path d={area} fill="url(#tdIncomeGrad)" />
        {hasForecast && (
          <path
            className="td-forecast"
            d={dashed}
            fill="none"
            stroke="var(--accent)"
            strokeWidth={3}
            strokeLinecap="round"
            strokeLinejoin="round"
            strokeOpacity={0.75}
            vectorEffect="non-scaling-stroke"
          />
        )}
        <path
          d={solid}
          fill="none"
          stroke="url(#tdIncomeStroke)"
          strokeWidth={3}
          strokeLinecap="round"
          strokeLinejoin="round"
          vectorEffect="non-scaling-stroke"
          filter="url(#tdIncomeGlow)"
          style={{ strokeDasharray: 1200, animation: 'tddraw 1.1s var(--ease) both' }}
        />
      </svg>

      {hasForecast && (
        <span
          className="absolute top-0 left-0 rounded-[var(--r-pill)] px-2 py-[3px] text-[10.5px] font-bold"
          style={{ background: 'var(--accent-bg)', color: 'var(--accent-600)' }}
        >
          نقطه‌چین: پیش‌بینی
        </span>
      )}

      {/* لایهٔ تعامل: هر ستون یک نقطه را هاور می‌کند (بدون state، فقط CSS) */}
      <div className="absolute inset-0 flex" style={{ alignItems: 'stretch' }}>
        {data.map((p, i) => {
          const isForecast = hasForecast && i >= nActual;
          return (
            <div key={i} className="td-hit relative flex-1 min-w-0">
              <span
                className="td-dot absolute block rounded-full border-2 border-[var(--surface)]"
                style={{
                  width: 10,
                  height: 10,
                  background: isForecast ? 'var(--accent)' : 'var(--primary)',
                  left: `${(i * stepX / W) * 100}%`,
                  top: `${(pts[i][1] / H) * 100}%`,
                  transform: 'translate(-50%, -50%)',
                }}
              />
              <span
                className="td-tip absolute whitespace-nowrap rounded-[var(--r-xs)] px-2 py-1 text-[11px] font-bold"
                style={{
                  left: `${(i * stepX / W) * 100}%`,
                  top: `${(pts[i][1] / H) * 100}%`,
                  transform: 'translate(-50%, calc(-100% - 12px))',
                  background: isForecast ? 'var(--accent)' : 'var(--text)',
                  color: 'var(--on-primary)',
                  boxShadow: 'var(--shadow)',
                }}
              >
                {isForecast ? `پیش‌بینی: ${faNum.format(values[i])}` : faNum.format(p.value)}
              </span>
            </div>
          );
        })}
      </div>

      <style>{`
        @keyframes tddraw { from { stroke-dashoffset: 1200 } to { stroke-dashoffset: 0 } }
        /* نقطه‌چینِ بخش پیش‌بینی — با non-scaling-stroke در محور کشیده نمی‌شود */
        .td-forecast { stroke-dasharray: 0.1 7; stroke-linecap: round; }
        .td-dot, .td-tip { opacity: 0; transition: opacity .14s var(--ease); pointer-events: none; }
        .td-hit:hover .td-dot, .td-hit:hover .td-tip { opacity: 1; }
      `}</style>
    </ChartFrame>
  );
}

function EmptyChart() {
  return (
    <div className="h-[300px] w-full grid place-items-center text-[13px] text-[var(--text-2)]">
      داده‌ای برای نمایش نیست
    </div>
  );
}
