/**
 * Non-side-effect class export for `<grid-ui>`.
 *
 * Importing this file gives you the class(es) without auto-registering the tag.
 * Useful for test isolation, subclassing with tag-name override, or selective
 * composition.
 *
 * The auto-register path stays at `@adia-ai/web-components/components/grid`
 * (which imports this file + calls `defineIfFree()`).
 *
 * @see ../../USAGE.md#registration--auto-vs-explicit
 */

/**
 * grid-ui — CSS grid layout primitive.
 *
 * <grid-ui columns="3" gap="lg">...</grid-ui>
 * <grid-ui columns="2" column-gap="2" row-gap="4">...</grid-ui>
 */

import { UIElement } from '../../core/element.js';
import { parseResponsive, breakpoint } from '../../core/responsive.js';

export class UIGrid extends UIElement {
  static properties = {
    columns:        { type: String, default: '3',  reflect: true },
    gap:            { type: String, default: 'md', reflect: true },
    columnGap:      { type: String, default: '',   reflect: true, attribute: 'column-gap' },
    rowGap:         { type: String, default: '',   reflect: true, attribute: 'row-gap' },
    // Minimum track width for columns="auto-fit"/"auto-fill" (any CSS length,
    // e.g. "240px", "16rem"). Drives the minmax() floor via --grid-min-col;
    // unset → the 12rem default. No effect on numeric columns.
    minColumnWidth: { type: String, default: '',   reflect: true, attribute: 'min-column-width' },
  };
  static template = () => null;

  render() {
    // Reading breakpoint.value inside render() subscribes this component to
    // the signal — UIElement re-runs render() whenever the viewport crosses
    // a breakpoint boundary (and also on prop changes as normal).
    const bp = breakpoint.value;

    // ── columns ──────────────────────────────────────────────────────────────
    // Responsive value: JS resolves + writes inline gridTemplateColumns.
    // Also forces gridAutoFlow:row + gridAutoColumns:auto, overriding the
    // default CSS which has grid-auto-flow:column (single-row spread) — that
    // default only makes sense when NO explicit template is set.
    // Scalar value: clear inline styles, CSS [columns="N"] rules take over.
    const cols = this.columns;
    if (cols?.includes('@')) {
      const resolved = parseResponsive(cols, bp);
      this.style.gridTemplateColumns = this.#colsToTemplate(resolved);
      this.style.gridAutoFlow        = resolved ? 'row'  : '';
      this.style.gridAutoColumns     = resolved ? 'auto' : '';
    } else {
      this.style.gridTemplateColumns = '';
      this.style.gridAutoFlow        = '';
      this.style.gridAutoColumns     = '';
    }

    // ── min-column-width ───────────────────────────────────────────────────────
    // Feeds the auto-fit/auto-fill minmax() floor (CSS + #colsToTemplate read
    // var(--grid-min-col, 12rem)). Unset → cleared → falls back to 12rem.
    if (this.minColumnWidth) this.style.setProperty('--grid-min-col', this.minColumnWidth);
    else this.style.removeProperty('--grid-min-col');

    // ── gap ───────────────────────────────────────────────────────────────────
    // Same pattern: responsive values set inline column/row-gap directly;
    // scalar values clear those and let the universal [gap="N"] token rules
    // in tokens.css handle everything via --a-gap.
    const gap = this.gap;
    if (gap?.includes('@')) {
      const v   = parseResponsive(gap, bp);
      const css = this.#gapToCss(v);
      this.style.columnGap = css;
      this.style.rowGap    = css;
    } else {
      this.style.columnGap = '';
      this.style.rowGap    = '';
    }
  }

  /** Map a resolved columns value to a CSS grid-template-columns string. */
  #colsToTemplate(v) {
    if (!v) return '';
    if (/^\d+$/.test(v)) return `repeat(${v}, 1fr)`;
    if (v === 'auto-fill') return 'repeat(auto-fill, minmax(var(--grid-min-col, 12rem), 1fr))';
    if (v === 'auto-fit')  return 'repeat(auto-fit,  minmax(var(--grid-min-col, 12rem), 1fr))';
    return v; // passthrough for custom template expressions
  }

  /** Map a resolved gap value to a CSS length / custom-property reference. */
  #gapToCss(v) {
    if (!v || v === '0') return '0';
    if (/^\d+$/.test(v)) return `var(--a-space-${v})`;
    return `var(--a-gap-${v})`;
  }
}
