/* Gráfica interactiva del dashboard — series con check, filtros de mes, export PNG */

const DASHBOARD_MONTH_NAMES = [
  'Enero', 'Febrero', 'Marzo', 'Abril', 'Mayo', 'Junio',
  'Julio', 'Agosto', 'Septiembre', 'Octubre', 'Noviembre', 'Diciembre',
];

const DEFAULT_DASHBOARD_CHART_SERIES = {
  pagos: true,
  tienda: true,
  total: true,
  egresos: true,
  egresosGastos: false,
  egresosNomina: false,
  egresosRetiros: false,
  neto: true,
};

const DASHBOARD_CHART_SERIES = [
  { id: 'pagos', label: 'Mensualidades', field: 'pagos', colorKey: 'primary', stack: 'ingreso' },
  { id: 'tienda', label: 'Tienda en línea', field: 'tienda', colorKey: 'accent', stack: 'ingreso' },
  { id: 'total', label: 'Ingresos totales', field: 'total', colorKey: 'success', chartType: 'line', dashed: true },
  { id: 'egresos', label: 'Egresos total', field: 'egresos', colorKey: 'danger', stack: 'egreso' },
  { id: 'egresosGastos', label: 'Gastos operativos', field: 'egresosGastos', colorKey: 'warning', stack: 'egreso' },
  { id: 'egresosNomina', label: 'Nómina', field: 'egresosNomina', colorKey: 'urgent', stack: 'egreso' },
  { id: 'egresosRetiros', label: 'Retiros', field: 'egresosRetiros', colorKey: 'danger', stack: 'egreso' },
  { id: 'neto', label: 'Balance neto', field: 'neto', colorKey: 'info', chartType: 'line' },
];

function getDashboardSeriesColor (theme, colorKey) {
  return theme?.[colorKey] || theme?.primary || '#3b82f6';
}

function getActiveDashboardSeries (seriesState, theme) {
  return DASHBOARD_CHART_SERIES
    .filter((s) => seriesState?.[s.id])
    .map((s) => ({
      ...s,
      color: getDashboardSeriesColor(theme, s.colorKey),
    }));
}

function monthSeriesValue (monthRow, field) {
  const n = Number(monthRow?.[field]);
  return Number.isFinite(n) ? n : 0;
}

function sumSeriesOverMonths (months, field) {
  return (months || []).reduce((acc, m) => acc + monthSeriesValue(m, field), 0);
}

function buildDashboardChartDatasets (months, seriesState, theme) {
  const active = getActiveDashboardSeries(seriesState, theme);
  return active.map((s) => ({
    id: s.id,
    label: s.label,
    values: (months || []).map((m) => monthSeriesValue(m, s.field)),
    color: s.color,
    chartType: s.chartType || 'bar',
    stack: undefined,
    dashed: !!s.dashed,
  }));
}

function describeChartFilter (chartFilter, year) {
  const short = typeof DASHBOARD_MONTH_LABELS !== 'undefined' ? DASHBOARD_MONTH_LABELS : [];
  const long = typeof DASHBOARD_MONTH_NAMES !== 'undefined' ? DASHBOARD_MONTH_NAMES : short;
  const monthName = (m) => long[m - 1] || short[m - 1] || `mes ${m}`;
  if (!chartFilter) return `Año ${year}`;
  if (chartFilter.mode === 'meses') {
    if (!chartFilter.selectedMonths?.length) return `Año ${year} · Sin meses seleccionados`;
    const names = chartFilter.selectedMonths.map((m) => `${monthName(m)} ${year}`).join(', ');
    return `Año ${year} · ${names}`;
  }
  const from = Math.min(chartFilter.rangeFrom || 1, chartFilter.rangeTo || 12);
  const to = Math.max(chartFilter.rangeFrom || 1, chartFilter.rangeTo || 12);
  if (from === to) return `Año ${year} · ${monthName(from)} ${year}`;
  return `Año ${year} · ${monthName(from)} a ${monthName(to)} ${year}`;
}

function buildDashboardChartExportContext (stats, chartFilter, chartYear, seriesState) {
  const s = stats || {};
  const months = typeof filterDashboardMonths === 'function'
    ? filterDashboardMonths(s.monthlySeries || [], chartFilter)
    : (s.monthlySeries || []);
  const year = chartYear || s.year || new Date().getFullYear();
  const active = getActiveDashboardSeries(seriesState || DEFAULT_DASHBOARD_CHART_SERIES, {});
  const seriesTotals = active.map((ser) => ({
    id: ser.id,
    label: ser.label,
    total: sumSeriesOverMonths(months, ser.field),
  }));
  const tableHeaders = ['Mes', ...active.map((x) => x.label)];
  const tableRows = months.map((m) => [
    m.label,
    ...active.map((x) => monthSeriesValue(m, x.field)),
  ]);
  const breakdown = typeof sumChartMonthsBreakdown === 'function'
    ? sumChartMonthsBreakdown(months)
    : null;
  const currentMonth = typeof describeDashboardCurrentMonth === 'function'
    ? describeDashboardCurrentMonth()
    : null;
  return {
    year,
    months,
    chartFilter,
    filterLabel: describeChartFilter(chartFilter, year),
    seriesState: { ...DEFAULT_DASHBOARD_CHART_SERIES, ...seriesState },
    activeSeries: active,
    seriesTotals,
    tableHeaders,
    tableRows,
    breakdown,
    currentMonth,
    fin: s.finance || {},
    s,
    generatedAt: new Date().toISOString(),
  };
}

/** PNG multi-serie (misma vista que el dashboard) */
async function renderDashboardFinanceChartPng ({ labels, datasets, width = 900, height = 420 }) {
  if (typeof Chart === 'undefined' || !labels?.length || !datasets?.length) return null;
  const canvas = document.createElement('canvas');
  canvas.width = width;
  canvas.height = height;
  const ctx = canvas.getContext('2d');
  const chartDatasets = datasets.map((d) => ({
    type: d.chartType === 'line' ? 'line' : 'bar',
    label: d.label,
    data: d.values,
    backgroundColor: d.chartType === 'line' ? d.color + '22' : d.color + (d.dashed ? '55' : 'cc'),
    borderColor: d.color,
    borderWidth: d.chartType === 'line' ? 3 : 1,
    borderDash: d.dashed ? [6, 4] : [],
    fill: d.chartType === 'line',
    tension: 0.25,
    stack: d.chartType === 'line' ? undefined : (d.stack || undefined),
    order: d.chartType === 'line' ? 0 : 1,
  }));
  const chart = new Chart(ctx, {
    type: 'bar',
    data: { labels, datasets: chartDatasets },
    options: {
      animation: false,
      responsive: false,
      interaction: { mode: 'index', intersect: false },
      plugins: {
        legend: { display: true, position: 'bottom', labels: { font: { size: 11 }, boxWidth: 14 } },
        tooltip: {
          callbacks: {
            label: (ctx) => {
              const v = ctx.parsed.y ?? 0;
              return `${ctx.dataset.label}: $${v.toLocaleString('es-MX')}`;
            },
          },
        },
      },
        scales: {
          x: { grid: { display: false } },
          y: {
            beginAtZero: true,
            ticks: {
              callback: (v) => `$${Number(v).toLocaleString('es-MX', { maximumFractionDigits: 0 })}`,
            },
          },
        },
    },
  });
  await new Promise((r) => requestAnimationFrame(() => requestAnimationFrame(r)));
  chart.update();
  await new Promise((r) => setTimeout(r, 100));
  const url = canvas.toDataURL('image/png', 1);
  chart.destroy();
  return url;
}

const DashboardSeriesChecklist = ({ theme, seriesState, onToggle, onSelectAll, onClearAll, months }) => {
  const isMobile = useIsMobile();
  const seriesCols = isMobile ? '1fr' : 'repeat(auto-fill, minmax(200px, 1fr))';
  const fmt = (n) => `$${(Number(n) || 0).toLocaleString('es-MX')}`;
  return (
    <div style={{
      display: 'grid',
      gap: 10,
      padding: 14,
      borderRadius: 10,
      background: theme.bgInput,
      border: `1px solid ${theme.border}`,
    }}>
      <div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'center', flexWrap: 'wrap', gap: 8 }}>
        <span style={{ fontSize: 11, fontWeight: 700, letterSpacing: 1, textTransform: 'uppercase', color: theme.textMute, fontFamily: 'Inter, sans-serif' }}>
          Series visibles en la gráfica
        </span>
        <div style={{ display: 'flex', gap: 6 }}>
          <button type="button" onClick={onSelectAll} style={{
            padding: '4px 10px', borderRadius: 6, border: `1px solid ${theme.border}`,
            background: theme.bgCard, fontSize: 11, cursor: 'pointer', color: theme.textDim,
          }}>Todas</button>
          <button type="button" onClick={onClearAll} style={{
            padding: '4px 10px', borderRadius: 6, border: `1px solid ${theme.border}`,
            background: theme.bgCard, fontSize: 11, cursor: 'pointer', color: theme.textDim,
          }}>Ninguna</button>
        </div>
      </div>
      <div className="tecos-dash-chart-series-grid" style={{ display: 'grid', gridTemplateColumns: seriesCols, gap: 8, width: '100%', maxWidth: '100%', minWidth: 0 }}>
        {DASHBOARD_CHART_SERIES.map((s) => {
          const on = !!seriesState[s.id];
          const color = getDashboardSeriesColor(theme, s.colorKey);
          const total = sumSeriesOverMonths(months, s.field);
          return (
            <label key={s.id} style={{
              display: 'flex', alignItems: 'flex-start', gap: 10, padding: 10, borderRadius: 8,
              border: `1.5px solid ${on ? color : theme.border}`,
              background: on ? `${color}14` : 'transparent',
              cursor: 'pointer', fontFamily: 'Inter, sans-serif',
            }}>
              <input
                type="checkbox"
                checked={on}
                onChange={() => onToggle(s.id)}
                style={{ marginTop: 3, accentColor: color }}
              />
              <div style={{ flex: 1, minWidth: 0 }}>
                <div style={{ display: 'flex', alignItems: 'center', gap: 6 }}>
                  <span style={{ width: 10, height: 10, borderRadius: 2, background: color, flexShrink: 0 }} />
                  <span style={{ fontSize: 12, fontWeight: 700, color: theme.text }}>{s.label}</span>
                </div>
                <div style={{ fontSize: 11, color: theme.textDim, marginTop: 4 }}>
                  Total periodo: <strong style={{ color: theme.text }}>{fmt(total)}</strong>
                </div>
              </div>
            </label>
          );
        })}
      </div>
    </div>
  );
};

const DashboardChartLiveSummary = ({ theme, months, seriesState, periodLabel }) => {
  const isMobile = useIsMobile();
  const summaryCols = isMobile ? '1fr' : 'repeat(auto-fill, minmax(140px, 1fr))';
  const active = getActiveDashboardSeries(seriesState, theme);
  if (!active.length) {
    return (
      <p style={{ fontSize: 13, color: theme.warning, fontFamily: 'Inter, sans-serif', margin: 0 }}>
        Selecciona al menos una serie para ver la gráfica.
      </p>
    );
  }
  const monthNames = (months || []).map((m) => `${m.label} ${m.year}`).join(', ') || 'ningún mes';
  return (
    <div>
      {periodLabel && (
        <p style={{ fontSize: 12, color: theme.textDim, margin: '0 0 10px', fontFamily: 'Inter, sans-serif' }}>
          Totales del periodo <strong style={{ color: theme.text }}>{periodLabel}</strong> ({monthNames})
        </p>
      )}
      <div className="tecos-dash-chart-summary-grid" style={{ display: 'grid', gridTemplateColumns: summaryCols, gap: 10, width: '100%', maxWidth: '100%', minWidth: 0 }}>
        {active.map((s) => (
          <div key={s.id} style={{
            padding: 12, borderRadius: 8, border: `1px solid ${s.color}44`, background: `${s.color}10`,
          }}>
            <div style={{ fontSize: 10, color: theme.textMute, fontWeight: 700, textTransform: 'uppercase' }}>{s.label}</div>
            <div style={{ fontFamily: 'Bebas Neue, sans-serif', fontSize: 24, color: theme.text, marginTop: 4 }}>
              ${sumSeriesOverMonths(months, s.field).toLocaleString('es-MX')}
            </div>
            <div style={{ fontSize: 10, color: theme.textDim }}>Suma de {months.length} mes(es) visibles</div>
          </div>
        ))}
      </div>
    </div>
  );
};

const DashboardInteractiveFinanceChart = ({ theme, months, seriesState, height = 440 }) => {
  const wrapRef = React.useRef(null);
  const canvasRef = React.useRef(null);
  const chartRef = React.useRef(null);
  const [chartLibReady, setChartLibReady] = React.useState(() => typeof Chart !== 'undefined');

  React.useEffect(() => {
    if (typeof Chart !== 'undefined') {
      setChartLibReady(true);
      return;
    }
    let cancelled = false;
    (async () => {
      try {
        if (typeof tecosEnsureChartJs === 'function') await tecosEnsureChartJs();
        else if (typeof tecosEnsureExportLibs === 'function') await tecosEnsureExportLibs();
      } catch (e) {
        console.warn('[Tecos] Chart.js no cargó:', e);
      }
      if (!cancelled && typeof Chart !== 'undefined') setChartLibReady(true);
    })();
    return () => { cancelled = true; };
  }, []);

  React.useEffect(() => {
    const canvas = canvasRef.current;
    if (!chartLibReady || !canvas || typeof Chart === 'undefined') return undefined;

    const labels = (months || []).map((m) => m.label);
    const datasets = buildDashboardChartDatasets(months, seriesState, theme);

    if (chartRef.current) {
      chartRef.current.destroy();
      chartRef.current = null;
    }

    if (!labels.length || !datasets.length) return undefined;

    const chartDatasets = datasets.map((d) => ({
      type: d.chartType === 'line' ? 'line' : 'bar',
      label: d.label,
      data: d.values,
      backgroundColor: d.chartType === 'line' ? d.color + '33' : d.color + (d.dashed ? '66' : 'cc'),
      borderColor: d.color,
      borderWidth: d.chartType === 'line' ? 3 : 1,
      borderDash: d.dashed ? [6, 4] : [],
      fill: d.chartType === 'line',
      tension: 0.3,
      order: d.chartType === 'line' ? 0 : 1,
    }));

    const chart = new Chart(canvas.getContext('2d'), {
      type: 'bar',
      data: { labels, datasets: chartDatasets },
      options: {
        responsive: true,
        maintainAspectRatio: false,
        interaction: { mode: 'index', intersect: false },
        plugins: {
          legend: {
            display: true,
            position: 'top',
            labels: { font: { size: 12, family: 'Inter, sans-serif' }, padding: 14, boxWidth: 16 },
          },
          tooltip: {
            backgroundColor: 'rgba(15,23,42,0.92)',
            titleFont: { size: 13, weight: 'bold' },
            bodyFont: { size: 12 },
            padding: 12,
            callbacks: {
              title: (items) => (items[0] ? `Mes: ${items[0].label}` : ''),
              label: (ctx) => {
                const v = ctx.parsed.y ?? 0;
                return ` ${ctx.dataset.label}: $${v.toLocaleString('es-MX')}`;
              },
              footer: (items) => {
                const sum = items.reduce((a, it) => a + (it.parsed.y || 0), 0);
                return `Suma visible: $${sum.toLocaleString('es-MX')}`;
              },
            },
          },
        },
        scales: {
          x: {
            grid: { display: false },
            ticks: { font: { size: 11, weight: '600' }, color: theme.textDim },
          },
          y: {
            beginAtZero: true,
            grid: { color: theme.border + '88' },
            ticks: {
              color: theme.textMute,
              callback: (v) => `$${Number(v).toLocaleString('es-MX', { maximumFractionDigits: 0 })}`,
            },
          },
        },
      },
    });
    chartRef.current = chart;

    const fitChart = () => {
      try { chart.resize(); } catch (_) { /* ignore */ }
    };
    requestAnimationFrame(() => requestAnimationFrame(fitChart));

    const wrap = wrapRef.current;
    let ro;
    if (wrap && typeof ResizeObserver !== 'undefined') {
      ro = new ResizeObserver(() => fitChart());
      ro.observe(wrap);
    }

    return () => {
      if (ro) ro.disconnect();
      if (chartRef.current) {
        chartRef.current.destroy();
        chartRef.current = null;
      }
    };
  }, [chartLibReady, months, seriesState, theme, height]);

  const labels = months || [];
  const datasets = buildDashboardChartDatasets(months, seriesState, theme);

  if (!chartLibReady) {
    return (
      <div style={{ height, display: 'grid', placeItems: 'center', color: theme.textDim, fontFamily: 'Inter, sans-serif', fontSize: 13 }}>
        Cargando gráfica…
      </div>
    );
  }

  if (!labels.length) {
    return (
      <div style={{ height, display: 'grid', placeItems: 'center', color: theme.textDim, fontFamily: 'Inter, sans-serif' }}>
        Sin datos en el periodo. Ajusta el año o los meses del filtro.
      </div>
    );
  }
  if (!datasets.length) {
    return (
      <div style={{ height, display: 'grid', placeItems: 'center', color: theme.warning, fontFamily: 'Inter, sans-serif' }}>
        Marca al menos una serie arriba para dibujar la gráfica.
      </div>
    );
  }

  return (
    <div
      ref={wrapRef}
      className="tecos-dash-chart-canvas-host"
      style={{ height, minHeight: height, position: 'relative', width: '100%', maxWidth: '100%', minWidth: 0, overflow: 'hidden' }}
    >
      <canvas ref={canvasRef} style={{ width: '100%', maxWidth: '100%', height: '100%', display: 'block' }} />
    </div>
  );
};

Object.assign(window, {
  DEFAULT_DASHBOARD_CHART_SERIES,
  DASHBOARD_CHART_SERIES,
  getActiveDashboardSeries,
  buildDashboardChartDatasets,
  buildDashboardChartExportContext,
  renderDashboardFinanceChartPng,
  DashboardSeriesChecklist,
  DashboardChartLiveSummary,
  DashboardInteractiveFinanceChart,
  describeChartFilter,
});
