/**
 * Configurable chart panel. Renders one ChartConfig as a Recharts chart,
 * with inline controls for type, metrics, granularity, and axis ranges.
 */

import { useMemo, useState } from 'react';
import {
  ResponsiveContainer,
  LineChart, Line,
  BarChart, Bar,
  AreaChart, Area,
  PieChart, Pie, Cell,
  XAxis, YAxis, Tooltip, Legend, CartesianGrid,
} from 'recharts';
import type { ChartConfig, ChartMetric, ChartType, ChartGranularity } from '@/types';
import { buildChartSeries } from '@/lib/stats/aggregate';
import { useAppStore } from '@/store/appStore';
import { fmtMoneyShort } from '@/lib/format';

const METRIC_LABELS: Record<ChartMetric, string> = {
  workValue: 'Work Value',
  payments: 'Payments',
  expenses: 'Expenses',
  netIncome: 'Net Income',
  cumulativePayments: 'Cumulative Payments',
  cumulativeNet: 'Cumulative Net',
};

const CHART_COLORS = [
  'var(--chart-1)', 'var(--chart-2)', 'var(--chart-3)',
  'var(--chart-4)', 'var(--chart-5)',
];

interface Props {
  config: ChartConfig;
  onChange: (patch: Partial<ChartConfig>) => void;
  onRemove?: () => void;
}

export function ChartPanel({ config, onChange, onRemove }: Props) {
  const work = useAppStore((s) => s.data.workEntries);
  const payments = useAppStore((s) => s.data.payments);
  const expenses = useAppStore((s) => s.data.expenses);

  const [showControls, setShowControls] = useState(false);

  const data = useMemo(
    () =>
      buildChartSeries(
        work,
        payments,
        expenses,
        config.metrics,
        config.granularity,
        config.rangeStart,
        config.rangeEnd,
      ),
    [work, payments, expenses, config],
  );

  const yDomain: [number | 'auto', number | 'auto'] = [
    config.yMin ?? 'auto',
    config.yMax ?? 'auto',
  ];

  const toggleMetric = (m: ChartMetric) => {
    const has = config.metrics.includes(m);
    const next = has
      ? config.metrics.filter((x) => x !== m)
      : [...config.metrics, m];
    if (next.length > 0) onChange({ metrics: next });
  };

  return (
    <div className="card" style={{ flex: 1, minHeight: 300, display: 'flex', flexDirection: 'column' }}>
      <div className="card-header">
        <input
          className="input input-inline"
          style={{ border: 'none', fontWeight: 600, fontSize: 14, background: 'transparent', width: '60%' }}
          value={config.title ?? ''}
          placeholder="Chart title"
          onChange={(e) => onChange({ title: e.target.value })}
        />
        <div className="flex gap-1">
          <button className="btn btn-sm btn-ghost" onClick={() => setShowControls(!showControls)} title="Configure">
            ⚙
          </button>
          {onRemove && (
            <button className="btn btn-sm btn-ghost text-danger" onClick={onRemove} title="Remove chart">
              ✕
            </button>
          )}
        </div>
      </div>

      {showControls && (
        <div className="flex-col gap-2 mb-4" style={{ padding: 12, background: 'var(--bg-elev-2)', borderRadius: 'var(--radius-sm)' }}>
          {/* Chart type */}
          <div className="flex items-center gap-2">
            <span className="text-sm text-muted" style={{ width: 80 }}>Type</span>
            <div className="btn-group">
              {(['line', 'bar', 'area', 'pie'] as ChartType[]).map((t) => (
                <button
                  key={t}
                  className={`btn btn-sm ${config.type === t ? 'active' : ''}`}
                  onClick={() => onChange({ type: t })}
                >
                  {t}
                </button>
              ))}
            </div>
          </div>

          {/* Granularity */}
          <div className="flex items-center gap-2">
            <span className="text-sm text-muted" style={{ width: 80 }}>Grain</span>
            <div className="btn-group">
              {(['day', 'week', 'month', 'year'] as ChartGranularity[]).map((g) => (
                <button
                  key={g}
                  className={`btn btn-sm ${config.granularity === g ? 'active' : ''}`}
                  onClick={() => onChange({ granularity: g })}
                >
                  {g}
                </button>
              ))}
            </div>
          </div>

          {/* Metrics */}
          <div className="flex items-center gap-2" style={{ flexWrap: 'wrap' }}>
            <span className="text-sm text-muted" style={{ width: 80 }}>Data</span>
            {(Object.keys(METRIC_LABELS) as ChartMetric[]).map((m) => (
              <label key={m} className="checkbox text-sm">
                <input
                  type="checkbox"
                  checked={config.metrics.includes(m)}
                  onChange={() => toggleMetric(m)}
                />
                {METRIC_LABELS[m]}
              </label>
            ))}
          </div>

          {/* X range */}
          <div className="flex items-center gap-2">
            <span className="text-sm text-muted" style={{ width: 80 }}>X range</span>
            <input
              type="date"
              className="input input-inline"
              style={{ width: 140 }}
              value={config.rangeStart ?? ''}
              onChange={(e) => onChange({ rangeStart: e.target.value || null })}
            />
            <span className="text-muted">to</span>
            <input
              type="date"
              className="input input-inline"
              style={{ width: 140 }}
              value={config.rangeEnd ?? ''}
              onChange={(e) => onChange({ rangeEnd: e.target.value || null })}
            />
          </div>

          {/* Y range */}
          <div className="flex items-center gap-2">
            <span className="text-sm text-muted" style={{ width: 80 }}>Y range</span>
            <input
              type="number"
              className="input input-inline"
              style={{ width: 100 }}
              placeholder="auto"
              value={config.yMin ?? ''}
              onChange={(e) => onChange({ yMin: e.target.value ? Number(e.target.value) : null })}
            />
            <span className="text-muted">to</span>
            <input
              type="number"
              className="input input-inline"
              style={{ width: 100 }}
              placeholder="auto"
              value={config.yMax ?? ''}
              onChange={(e) => onChange({ yMax: e.target.value ? Number(e.target.value) : null })}
            />
          </div>
        </div>
      )}

      {/* Chart render */}
      <div style={{ flex: 1, minHeight: 200 }}>
        {data.length === 0 ? (
          <div className="flex items-center justify-between full-height text-muted" style={{ justifyContent: 'center' }}>
            No data to display
          </div>
        ) : (
          <ResponsiveContainer width="100%" height="100%">
            {renderChart(config, data, yDomain)}
          </ResponsiveContainer>
        )}
      </div>
    </div>
  );
}

function renderChart(
  config: ChartConfig,
  data: ReturnType<typeof buildChartSeries>,
  yDomain: [number | 'auto', number | 'auto'],
) {
  const common = {
    data,
    margin: { top: 5, right: 10, bottom: 5, left: 0 },
  };

  const axes = (
    <>
      <CartesianGrid strokeDasharray="3 3" stroke="var(--border)" />
      <XAxis dataKey="label" stroke="var(--fg-muted)" fontSize={11} />
      <YAxis
        stroke="var(--fg-muted)"
        fontSize={11}
        domain={yDomain}
        tickFormatter={(v) => fmtMoneyShort(v)}
      />
      <Tooltip
        contentStyle={{
          background: 'var(--bg-elev)',
          border: '1px solid var(--border)',
          borderRadius: 'var(--radius-sm)',
        }}
        formatter={(v: number) => fmtMoneyShort(v)}
      />
      <Legend wrapperStyle={{ fontSize: 12 }} />
    </>
  );

  switch (config.type) {
    case 'line':
      return (
        <LineChart {...common}>
          {axes}
          {config.metrics.map((m, i) => (
            <Line
              key={m}
              type="monotone"
              dataKey={m}
              name={METRIC_LABELS[m]}
              stroke={CHART_COLORS[i % CHART_COLORS.length]}
              strokeWidth={2}
              dot={false}
            />
          ))}
        </LineChart>
      );
    case 'bar':
      return (
        <BarChart {...common}>
          {axes}
          {config.metrics.map((m, i) => (
            <Bar key={m} dataKey={m} name={METRIC_LABELS[m]} fill={CHART_COLORS[i % CHART_COLORS.length]} />
          ))}
        </BarChart>
      );
    case 'area':
      return (
        <AreaChart {...common}>
          {axes}
          {config.metrics.map((m, i) => (
            <Area
              key={m}
              type="monotone"
              dataKey={m}
              name={METRIC_LABELS[m]}
              stroke={CHART_COLORS[i % CHART_COLORS.length]}
              fill={CHART_COLORS[i % CHART_COLORS.length]}
              fillOpacity={0.3}
            />
          ))}
        </AreaChart>
      );
    case 'pie': {
      // Pie: sum each metric over the range
      const totals = config.metrics.map((m) => ({
        name: METRIC_LABELS[m],
        value: data.reduce((s, d) => s + (Number(d[m]) || 0), 0),
      }));
      return (
        <PieChart>
          <Pie data={totals} dataKey="value" nameKey="name" outerRadius="80%" label>
            {totals.map((_, i) => (
              <Cell key={i} fill={CHART_COLORS[i % CHART_COLORS.length]} />
            ))}
          </Pie>
          <Tooltip formatter={(v: number) => fmtMoneyShort(v)} />
          <Legend wrapperStyle={{ fontSize: 12 }} />
        </PieChart>
      );
    }
  }
}
