/**
 * Theme Builder — Axes & grid panel (docs/chart-theming-scope.md §5).
 *
 * Structured controls over the base `axis` config only — grid, ticks, the domain
 * line, labels, and title. The 25 per-channel variants (`axisX`, `axisY`,
 * `axisBand`, …) stay in the JSON; this is the common surface a brand actually
 * tunes. Axis *type* (label/title size and weight) lives in the Type panel.
 */

import type { JsonObject } from '@core/spec-config';
import {
  asBoolean,
  asNumber,
  asString,
  type ConfigPath,
  countSet,
  getConfigValue,
} from '@core/theme-controls';
import { useConfigSetter } from '../stores/CustomThemeStore';
import { Accordion, type AccordionSection, ColorRow, NumberRow, SelectRow } from './ThemeFields';
import type { SelectControlOption } from './SelectControl';

const GRID: ConfigPath = ['axis', 'grid'];
const GRID_COLOR: ConfigPath = ['axis', 'gridColor'];
const GRID_DASH: ConfigPath = ['axis', 'gridDash'];
const GRID_WIDTH: ConfigPath = ['axis', 'gridWidth'];
const DOMAIN_COLOR: ConfigPath = ['axis', 'domainColor'];
const DOMAIN_WIDTH: ConfigPath = ['axis', 'domainWidth'];
const LABEL_COLOR: ConfigPath = ['axis', 'labelColor'];
const LABEL_ANGLE: ConfigPath = ['axis', 'labelAngle'];
const LABEL_PADDING: ConfigPath = ['axis', 'labelPadding'];
const TITLE_COLOR: ConfigPath = ['axis', 'titleColor'];
const TICKS: ConfigPath = ['axis', 'ticks'];
const TICK_COLOR: ConfigPath = ['axis', 'tickColor'];
const TICK_SIZE: ConfigPath = ['axis', 'tickSize'];

const GRID_GREY = '#888888';

// Visibility: tri-state (theme default · shown · hidden) over a boolean — shared
// by grid lines and ticks (both `boolean | undefined` config keys).
type ShowState = '' | 'true' | 'false';
const showOptions: SelectControlOption<ShowState>[] = [
  { value: '', label: 'Theme default' },
  { value: 'true', label: 'Shown' },
  { value: 'false', label: 'Hidden' },
];
const showState = (v: boolean | undefined): ShowState =>
  v === undefined ? '' : v ? 'true' : 'false';

// Dash presets, matched by array shape; an unrecognised array reads as no preset
// (the trigger shows "—") so the control never misreports a hand-authored dash.
type DashStyle = '' | 'solid' | 'dotted' | 'dashed' | 'custom';
const dashOptions: SelectControlOption<DashStyle>[] = [
  { value: '', label: 'Theme default' },
  { value: 'solid', label: 'Solid' },
  { value: 'dotted', label: 'Dotted' },
  { value: 'dashed', label: 'Dashed' },
];
const DASH_VALUES: Record<Exclude<DashStyle, '' | 'custom'>, number[]> = {
  solid: [],
  dotted: [2, 2],
  dashed: [6, 3],
};
const dashStyle = (v: unknown): DashStyle => {
  if (v === undefined) return '';
  if (!Array.isArray(v)) return 'custom';
  if (v.length === 0) return 'solid';
  if (v.length === 2 && v[0] === 2 && v[1] === 2) return 'dotted';
  if (v.length === 2 && v[0] === 6 && v[1] === 3) return 'dashed';
  return 'custom';
};

export function AxesControls({ config }: { config: JsonObject }) {
  const set = useConfigSetter();

  const sections: AccordionSection[] = [
    {
      id: 'grid',
      title: 'Grid',
      hint: 'Reference lines behind the marks.',
      badge: countSet(config, [GRID, GRID_COLOR, GRID_DASH, GRID_WIDTH]),
      children: (
        <>
          <SelectRow
            id="axes-grid"
            label="Grid lines"
            options={showOptions}
            value={showState(asBoolean(getConfigValue(config, GRID)))}
            onSelect={(s) => set(GRID, s === '' ? undefined : s === 'true')}
          />
          <ColorRow
            label="Grid color"
            value={asString(getConfigValue(config, GRID_COLOR))}
            fallback={GRID_GREY}
            onChange={(hex) => set(GRID_COLOR, hex)}
            onClear={() => set(GRID_COLOR, undefined)}
          />
          <SelectRow
            id="axes-grid-dash"
            label="Grid style"
            options={dashOptions}
            value={dashStyle(getConfigValue(config, GRID_DASH))}
            onSelect={(s) =>
              set(GRID_DASH, s === '' ? undefined : DASH_VALUES[s as keyof typeof DASH_VALUES])
            }
          />
          <NumberRow
            label="Grid width"
            value={asNumber(getConfigValue(config, GRID_WIDTH))}
            min={0}
            unit="px"
            onChange={(n) => set(GRID_WIDTH, n)}
          />
        </>
      ),
    },
    {
      id: 'ticks',
      title: 'Ticks',
      hint: 'The marks along the axis line.',
      badge: countSet(config, [TICKS, TICK_COLOR, TICK_SIZE]),
      children: (
        <>
          <SelectRow
            id="axes-ticks"
            label="Ticks"
            options={showOptions}
            value={showState(asBoolean(getConfigValue(config, TICKS)))}
            onSelect={(s) => set(TICKS, s === '' ? undefined : s === 'true')}
          />
          <ColorRow
            label="Tick color"
            value={asString(getConfigValue(config, TICK_COLOR))}
            fallback={GRID_GREY}
            onChange={(hex) => set(TICK_COLOR, hex)}
            onClear={() => set(TICK_COLOR, undefined)}
          />
          <NumberRow
            label="Tick size"
            value={asNumber(getConfigValue(config, TICK_SIZE))}
            min={0}
            unit="px"
            onChange={(n) => set(TICK_SIZE, n)}
          />
        </>
      ),
    },
    {
      id: 'domain',
      title: 'Domain & labels',
      hint: 'The axis line, its tick labels, and title.',
      badge: countSet(config, [
        DOMAIN_COLOR,
        DOMAIN_WIDTH,
        LABEL_COLOR,
        LABEL_ANGLE,
        LABEL_PADDING,
        TITLE_COLOR,
      ]),
      children: (
        <>
          <ColorRow
            label="Domain line"
            value={asString(getConfigValue(config, DOMAIN_COLOR))}
            fallback={GRID_GREY}
            onChange={(hex) => set(DOMAIN_COLOR, hex)}
            onClear={() => set(DOMAIN_COLOR, undefined)}
          />
          <NumberRow
            label="Domain width"
            value={asNumber(getConfigValue(config, DOMAIN_WIDTH))}
            min={0}
            unit="px"
            onChange={(n) => set(DOMAIN_WIDTH, n)}
          />
          <ColorRow
            label="Label color"
            value={asString(getConfigValue(config, LABEL_COLOR))}
            fallback={GRID_GREY}
            onChange={(hex) => set(LABEL_COLOR, hex)}
            onClear={() => set(LABEL_COLOR, undefined)}
          />
          <NumberRow
            label="Label angle"
            value={asNumber(getConfigValue(config, LABEL_ANGLE))}
            min={-90}
            max={90}
            unit="°"
            onChange={(n) => set(LABEL_ANGLE, n)}
          />
          <NumberRow
            label="Label padding"
            value={asNumber(getConfigValue(config, LABEL_PADDING))}
            min={0}
            unit="px"
            onChange={(n) => set(LABEL_PADDING, n)}
          />
          <ColorRow
            label="Title color"
            value={asString(getConfigValue(config, TITLE_COLOR))}
            fallback={GRID_GREY}
            onChange={(hex) => set(TITLE_COLOR, hex)}
            onClear={() => set(TITLE_COLOR, undefined)}
          />
        </>
      ),
    },
  ];

  return <Accordion sections={sections} idPrefix="axes" />;
}
