'use client'

import {
  Area,
  CartesianGrid,
  ComposedChart,
  Legend,
  Line,
  ReferenceArea,
  ReferenceLine,
  ResponsiveContainer,
  Tooltip,
  XAxis,
  YAxis,
} from 'recharts'

import { useI18n } from '@/components/providers/i18n-provider'
import { CHART_COLORS } from '@/lib/ui/state-styles'
import { cn } from '@/lib/cn'

export interface SeriesConfig {
  key: string
  label: string
  color: string
  type?: 'line' | 'area'
  strokeDasharray?: string
  fillOpacity?: number
  yAxisId?: 'left' | 'right'
  hidden?: boolean
}

export interface BandConfig {
  lowerKey: string
  upperKey: string
  label: string
  color: string
}

export interface MarkerConfig {
  x: number
  label: string
  color?: string
}

export interface TimeSeriesPoint {
  ts: number
  [key: string]: number | null | undefined
}

/**
 * The chart used everywhere a value moves over time.
 *
 * Two decisions worth noting:
 *  • The x-axis is reversed under RTL so time still reads in the document's own
 *    direction — a right-to-left reader should not have to scan a timeline backwards.
 *  • Every chart is paired with an equivalent data table for screen readers, hidden
 *    visually but present in the accessibility tree, because an SVG path communicates
 *    nothing on its own (§47).
 */
export function TimeSeriesChart({
  data,
  series,
  band,
  markers,
  height = 260,
  yLabel,
  rightLabel,
  yDomain,
  rightDomain,
  className,
  ariaLabel,
  showLegend = true,
  valueFormatter,
}: {
  data: TimeSeriesPoint[]
  series: SeriesConfig[]
  band?: BandConfig
  markers?: MarkerConfig[]
  height?: number
  yLabel?: string
  rightLabel?: string
  yDomain?: [number | 'auto', number | 'auto']
  rightDomain?: [number | 'auto', number | 'auto']
  className?: string
  ariaLabel: string
  showLegend?: boolean
  valueFormatter?: (value: number, key: string) => string
}) {
  const { locale, time, n } = useI18n()
  const rtl = locale === 'ar'
  const visible = series.filter((entry) => !entry.hidden)

  const format = (value: number, key: string) =>
    valueFormatter ? valueFormatter(value, key) : n(value, { maximumFractionDigits: 1 })

  return (
    <div className={cn('w-full', className)}>
      <div style={{ height }} role="img" aria-label={ariaLabel}>
        <ResponsiveContainer width="100%" height="100%">
          <ComposedChart data={data} margin={{ top: 8, right: 12, bottom: 4, left: 12 }}>
            <defs>
              {visible.map((entry) => (
                <linearGradient
                  key={entry.key}
                  id={`fill-${entry.key}`}
                  x1="0"
                  y1="0"
                  x2="0"
                  y2="1"
                >
                  <stop offset="0%" stopColor={entry.color} stopOpacity={0.32} />
                  <stop offset="100%" stopColor={entry.color} stopOpacity={0} />
                </linearGradient>
              ))}
            </defs>

            <CartesianGrid stroke={CHART_COLORS.grid} strokeDasharray="3 3" vertical={false} />

            <XAxis
              dataKey="ts"
              type="number"
              scale="time"
              domain={['dataMin', 'dataMax']}
              reversed={rtl}
              tickFormatter={(value: number) => time(value)}
              tick={{ fill: CHART_COLORS.axis, fontSize: 11 }}
              stroke={CHART_COLORS.grid}
              minTickGap={40}
            />

            <YAxis
              yAxisId="left"
              orientation={rtl ? 'right' : 'left'}
              domain={yDomain ?? ['auto', 'auto']}
              tick={{ fill: CHART_COLORS.axis, fontSize: 11 }}
              stroke={CHART_COLORS.grid}
              width={48}
              label={
                yLabel
                  ? {
                      value: yLabel,
                      angle: -90,
                      position: 'insideLeft',
                      fill: CHART_COLORS.axis,
                      fontSize: 11,
                    }
                  : undefined
              }
            />

            {rightLabel ? (
              <YAxis
                yAxisId="right"
                orientation={rtl ? 'left' : 'right'}
                domain={rightDomain ?? ['auto', 'auto']}
                tick={{ fill: CHART_COLORS.axis, fontSize: 11 }}
                stroke={CHART_COLORS.grid}
                width={48}
              />
            ) : null}

            {band ? (
              <>
                <Area
                  yAxisId="left"
                  dataKey={band.upperKey}
                  stroke="none"
                  fill={band.color}
                  fillOpacity={0.16}
                  isAnimationActive={false}
                  name={band.label}
                  stackId="band"
                />
                <Area
                  yAxisId="left"
                  dataKey={band.lowerKey}
                  stroke="none"
                  fill={CHART_COLORS.grid}
                  fillOpacity={0}
                  isAnimationActive={false}
                  legendType="none"
                  stackId="bandLower"
                />
              </>
            ) : null}

            {markers?.map((marker) => (
              <ReferenceLine
                key={`${marker.x}-${marker.label}`}
                yAxisId="left"
                x={marker.x}
                stroke={marker.color ?? CHART_COLORS.primary}
                strokeDasharray="4 4"
                label={{
                  value: marker.label,
                  fill: marker.color ?? CHART_COLORS.primary,
                  fontSize: 10,
                  position: 'insideTopRight',
                }}
              />
            ))}

            {visible.map((entry) =>
              entry.type === 'area' ? (
                <Area
                  key={entry.key}
                  yAxisId={entry.yAxisId ?? 'left'}
                  dataKey={entry.key}
                  name={entry.label}
                  stroke={entry.color}
                  strokeWidth={2}
                  fill={`url(#fill-${entry.key})`}
                  fillOpacity={entry.fillOpacity ?? 1}
                  isAnimationActive={false}
                  dot={false}
                  connectNulls
                />
              ) : (
                <Line
                  key={entry.key}
                  yAxisId={entry.yAxisId ?? 'left'}
                  dataKey={entry.key}
                  name={entry.label}
                  stroke={entry.color}
                  strokeWidth={2}
                  strokeDasharray={entry.strokeDasharray}
                  isAnimationActive={false}
                  dot={false}
                  connectNulls
                />
              ),
            )}

            <Tooltip
              contentStyle={{
                backgroundColor: '#0b1220',
                border: '1px solid #1e2d47',
                borderRadius: 10,
                fontSize: 12,
                direction: rtl ? 'rtl' : 'ltr',
              }}
              labelStyle={{ color: '#93a5c4', marginBottom: 4 }}
              labelFormatter={(value) => time(Number(value))}
              formatter={(value, name) => [format(Number(value), String(name)), name]}
            />

            {showLegend ? (
              <Legend
                wrapperStyle={{
                  fontSize: 11,
                  color: '#93a5c4',
                  paddingTop: 8,
                  direction: rtl ? 'rtl' : 'ltr',
                }}
                iconType="plainline"
              />
            ) : null}
          </ComposedChart>
        </ResponsiveContainer>
      </div>

      <ChartDataTable data={data} series={visible} caption={ariaLabel} format={format} />
    </div>
  )
}

/** The screen-reader equivalent of the chart above. */
function ChartDataTable({
  data,
  series,
  caption,
  format,
}: {
  data: TimeSeriesPoint[]
  series: SeriesConfig[]
  caption: string
  format: (value: number, key: string) => string
}) {
  const { t, dateTime } = useI18n()
  // Long series are sampled: reading 500 rows aloud helps nobody, and the shape of the
  // data is what a summary needs to convey.
  const step = Math.max(1, Math.ceil(data.length / 24))
  const rows = data.filter((_, index) => index % step === 0)

  // The wrapper carries `sr-only`, not the table: a <table> ignores `width: 1px` under
  // auto table layout and grows to its content, which pushed every chart page wider than
  // a phone viewport. A <div> respects the width and clips it.
  return (
    <div className="sr-only">
      <table>
        <caption>
          {caption}. {t('a11y.chartSummary')}
        </caption>
        <thead>
          <tr>
            <th scope="col">{t('common.timestamp')}</th>
            {series.map((entry) => (
              <th key={entry.key} scope="col">
                {entry.label}
              </th>
            ))}
          </tr>
        </thead>
        <tbody>
          {rows.map((row) => (
            <tr key={row.ts}>
              <th scope="row">{dateTime(row.ts)}</th>
              {series.map((entry) => {
                const value = row[entry.key]
                return (
                  <td key={entry.key}>
                    {typeof value === 'number' ? format(value, entry.key) : t('common.na')}
                  </td>
                )
              })}
            </tr>
          ))}
        </tbody>
      </table>
    </div>
  )
}

/** A compact inline trend line, for table cells and stat tiles. */
export function Sparkline({
  data,
  color = CHART_COLORS.primary,
  height = 32,
  ariaLabel,
}: {
  data: Array<{ ts: number; value: number }>
  color?: string
  height?: number
  ariaLabel: string
}) {
  if (data.length < 2) return null
  const values = data.map((point) => point.value)
  const min = Math.min(...values)
  const max = Math.max(...values)
  const span = max - min || 1

  const points = data
    .map((point, index) => {
      const x = (index / (data.length - 1)) * 100
      const y = 100 - ((point.value - min) / span) * 100
      return `${x.toFixed(2)},${y.toFixed(2)}`
    })
    .join(' ')

  return (
    <svg
      viewBox="0 0 100 100"
      preserveAspectRatio="none"
      style={{ height }}
      className="w-full"
      role="img"
      aria-label={ariaLabel}
    >
      <polyline
        points={points}
        fill="none"
        stroke={color}
        strokeWidth="2.5"
        vectorEffect="non-scaling-stroke"
        strokeLinecap="round"
        strokeLinejoin="round"
      />
    </svg>
  )
}

export { ReferenceArea }
