/**
 * Non-side-effect class export for `<number-format-ui>`.
 *
 * Importing this file gives you the class 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/number-format`
 * (which imports this file + calls `defineIfFree()`).
 *
 * @see ../../USAGE.md#registration--auto-vs-explicit
 */

/**
 * <number-format-ui value="1234567.89"></number-format-ui>             → 1,234,567.89
 * <number-format-ui value="1299.99" number-style="currency" currency="USD"></number-format-ui>  → $1,299.99
 * <number-format-ui value="0.876" number-style="percent"></number-format-ui>                    → 87.6%
 * <number-format-ui value="1234567" notation="compact"></number-format-ui>                       → 1.2M
 *
 * Read-only display primitive wrapping `Intl.NumberFormat`. Distinct
 * from `<input-ui type="number">` (a form-input primitive).
 */

import { UIElement } from '../../core/element.js';

export class UINumberFormat extends UIElement {
  static properties = {
    value:                  { type: Number, default: 0,         reflect: true },
    numberStyle:            { type: String, default: 'decimal', reflect: true, attribute: 'number-style' },
    currency:               { type: String, default: '',        reflect: true },
    unit:                   { type: String, default: '',        reflect: true },
    notation:               { type: String, default: 'standard', reflect: true },
    compactDisplay:         { type: String, default: 'short',   reflect: true, attribute: 'compact-display' },
    minimumFractionDigits:  { type: Number, default: 0,         reflect: true, attribute: 'minimum-fraction-digits' },
    maximumFractionDigits:  { type: Number, default: 2,         reflect: true, attribute: 'maximum-fraction-digits' },
    locale:                 { type: String, default: '',        reflect: true },
    signDisplay:            { type: String, default: 'auto',    reflect: true, attribute: 'sign-display' },
  };

  static template = () => null;

  #resolveLocale() {
    if (this.locale) return this.locale;
    return this.ownerDocument?.documentElement?.lang || undefined;
  }

  #format() {
    const v = Number(this.value);
    if (!Number.isFinite(v)) return '';

    // Validate required dependent props per style.
    if (this.numberStyle === 'currency' && !this.currency) return '';
    if (this.numberStyle === 'unit' && !this.unit) return '';

    /** @type {Intl.NumberFormatOptions} */
    const opts = {
      style: this.numberStyle,
      notation: this.notation,
      signDisplay: this.signDisplay,
    };
    if (this.numberStyle === 'currency') opts.currency = this.currency;
    if (this.numberStyle === 'unit')     opts.unit = this.unit;
    if (this.notation === 'compact')     opts.compactDisplay = this.compactDisplay;
    // Honor min/max fraction digits when explicitly set. The defaults
    // (0 / 2) are reasonable for decimal+currency; compact notation
    // typically wants 1 max but we let consumers override.
    if (Number.isFinite(this.minimumFractionDigits)) opts.minimumFractionDigits = this.minimumFractionDigits;
    if (Number.isFinite(this.maximumFractionDigits)) opts.maximumFractionDigits = this.maximumFractionDigits;

    try {
      return new Intl.NumberFormat(this.#resolveLocale(), opts).format(v);
    } catch {
      return String(v);
    }
  }

  connected() {
    super.connected();
    // No special role — the rendered text is read by AT naturally; we
    // expose the raw value via aria-label for screen-reader clarity in
    // contexts where the formatted glyphs ("€", "M") might be parsed
    // unpredictably by different readers.
  }

  render() {
    const text = this.#format();
    this.textContent = text;
    // Mirror raw value via aria-label so screen readers can read the
    // underlying number alongside the formatted glyphs.
    if (text && Number.isFinite(Number(this.value))) {
      this.setAttribute('aria-label', `${text} (raw: ${this.value})`);
    } else {
      this.removeAttribute('aria-label');
    }
  }
}
