/**
 * Theme Builder — Layout panel (docs/chart-theming-scope.md §5).
 *
 * Structured controls over the draft config's surfaces and spacing: the chart
 * `background`, the plot area's `view` fill / border / corner radius, outer
 * `padding`, and the default chart size. Fill controls are tri-state (theme
 * default · transparent/none · custom color) because "transparent" is a
 * meaningful, distinct choice from "unset" here — the house style sets
 * `background` and `view.stroke` to transparent, and stock Vega-Lite defaults
 * them to white / `#ddd`.
 */

import type { JsonObject } from '@core/spec-config';
import { isJsonObject } from '@core/spec-config';
import {
  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';
import styles from './ThemeFields.module.css';

const BACKGROUND: ConfigPath = ['background'];
const VIEW_FILL: ConfigPath = ['view', 'fill'];
const VIEW_STROKE: ConfigPath = ['view', 'stroke'];
const VIEW_RADIUS: ConfigPath = ['view', 'cornerRadius'];
const PADDING: ConfigPath = ['padding'];
const VIEW_WIDTH: ConfigPath = ['view', 'continuousWidth'];
const VIEW_HEIGHT: ConfigPath = ['view', 'continuousHeight'];
const VIEW_STEP: ConfigPath = ['view', 'step'];

type FillMode = 'default' | 'transparent' | 'custom';

const fillMode = (v: unknown): FillMode =>
  v === undefined ? 'default' : v === 'transparent' ? 'transparent' : 'custom';

const bgOptions: SelectControlOption<FillMode>[] = [
  { value: 'default', label: 'Theme default' },
  { value: 'transparent', label: 'Transparent' },
  { value: 'custom', label: 'Custom color' },
];
// Same modes; "None" reads better than "Transparent" for a border.
const strokeOptions: SelectControlOption<FillMode>[] = [
  { value: 'default', label: 'Theme default' },
  { value: 'transparent', label: 'None' },
  { value: 'custom', label: 'Custom color' },
];

const fillValue = (mode: FillMode, current: string | undefined, seed: string): unknown =>
  mode === 'default' ? undefined : mode === 'transparent' ? 'transparent' : (current ?? seed);

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

  const bg = asString(getConfigValue(config, BACKGROUND));
  const bgMode = fillMode(getConfigValue(config, BACKGROUND));
  const viewFill = asString(getConfigValue(config, VIEW_FILL));
  const stroke = asString(getConfigValue(config, VIEW_STROKE));
  const strokeMode = fillMode(getConfigValue(config, VIEW_STROKE));
  const radius = asNumber(getConfigValue(config, VIEW_RADIUS));
  const padding = getConfigValue(config, PADDING);
  const paddingNum = asNumber(padding);

  const sections: AccordionSection[] = [
    {
      id: 'background',
      title: 'Background',
      hint: 'Fill behind the whole chart, padding included.',
      badge: countSet(config, [BACKGROUND]),
      children: (
        <>
          <SelectRow
            id="layout-bg-mode"
            label="Background"
            options={bgOptions}
            value={bgMode}
            onSelect={(m) => set(BACKGROUND, fillValue(m, bg, '#ffffff'))}
          />
          {bgMode === 'custom' && (
            <ColorRow
              label="Color"
              name="Background color"
              value={bg}
              fallback="#ffffff"
              onChange={(hex) => set(BACKGROUND, hex)}
            />
          )}
        </>
      ),
    },
    {
      id: 'plot',
      title: 'Plot area',
      hint: 'The plotting rectangle inside the axes.',
      badge: countSet(config, [VIEW_FILL, VIEW_STROKE, VIEW_RADIUS]),
      children: (
        <>
          <ColorRow
            label="Fill"
            name="Plot area fill"
            value={viewFill}
            fallback="#ffffff"
            onChange={(hex) => set(VIEW_FILL, hex)}
            onClear={() => set(VIEW_FILL, undefined)}
          />
          <SelectRow
            id="layout-stroke-mode"
            label="Border"
            options={strokeOptions}
            value={strokeMode}
            onSelect={(m) => set(VIEW_STROKE, fillValue(m, stroke, '#cccccc'))}
          />
          {strokeMode === 'custom' && (
            <ColorRow
              label="Border color"
              value={stroke}
              fallback="#cccccc"
              onChange={(hex) => set(VIEW_STROKE, hex)}
            />
          )}
          <NumberRow
            label="Corner radius"
            value={radius}
            min={0}
            unit="px"
            onChange={(n) => set(VIEW_RADIUS, n)}
          />
        </>
      ),
    },
    {
      id: 'spacing',
      title: 'Spacing',
      hint: 'Margin between the chart and its container edge.',
      badge: countSet(config, [PADDING]),
      children: isJsonObject(padding) ? (
        <p className={styles.hint}>
          Padding is set per-side as an object — edit it in the JSON below.
        </p>
      ) : (
        <NumberRow
          label="Padding"
          value={paddingNum}
          min={0}
          unit="px"
          onChange={(n) => set(PADDING, n)}
        />
      ),
    },
    {
      id: 'size',
      title: 'Default size',
      hint: "The plot size when a spec doesn't set its own width/height.",
      badge: countSet(config, [VIEW_WIDTH, VIEW_HEIGHT, VIEW_STEP]),
      children: (
        <>
          <NumberRow
            label="Width"
            name="Default width"
            value={asNumber(getConfigValue(config, VIEW_WIDTH))}
            min={0}
            unit="px"
            onChange={(n) => set(VIEW_WIDTH, n)}
          />
          <NumberRow
            label="Height"
            name="Default height"
            value={asNumber(getConfigValue(config, VIEW_HEIGHT))}
            min={0}
            unit="px"
            onChange={(n) => set(VIEW_HEIGHT, n)}
          />
          <NumberRow
            label="Step"
            name="Discrete step"
            value={asNumber(getConfigValue(config, VIEW_STEP))}
            min={0}
            unit="px"
            onChange={(n) => set(VIEW_STEP, n)}
          />
        </>
      ),
    },
  ];

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