/**
 * color-picker-ui #parseValue tests — §201 (v0.5.7, FEEDBACK-13 §1 +
 * FEEDBACK-14 §2 co-credited).
 *
 * Verifies the relaxed `oklch(L C H)` parser accepts:
 *   - Numeric channels (regression — the v0.5.6 baseline)
 *   - `NaN` on any channel (culori chromaless convention; coerces to 0)
 *   - `none` on any channel (CSS Color L4 powerless syntax; coerces to 0)
 *   - Percent on L (e.g. `oklch(53% 0.05 240)`; divides by 100)
 *
 * Plus:
 *   - Truly malformed input emits ONE console.warn per element (WeakSet dedup),
 *     not one per #parseValue call.
 *   - Hex pass-through remains intact.
 */

import { describe, it, expect, beforeEach, vi } from 'vitest';
import '../../core/element.js';
import './color-picker.js';

const tick = () => new Promise((r) => queueMicrotask(r));

function mount(html) {
  const wrap = document.createElement('div');
  wrap.innerHTML = html;
  document.body.appendChild(wrap);
  return wrap.firstElementChild;
}

describe('color-picker-ui #parseValue (§201)', () => {
  beforeEach(() => { document.body.innerHTML = ''; });

  it('accepts numeric oklch (baseline regression)', async () => {
    const p = mount('<color-picker-ui format="oklch" value="oklch(0.6 0.15 240)"></color-picker-ui>');
    await tick();
    // Read back via the public value getter — round-tripped through the parser.
    expect(p.value).toMatch(/oklch/);
  });

  it('accepts NaN hue (culori chromaless convention)', async () => {
    const warn = vi.spyOn(console, 'warn').mockImplementation(() => {});
    const p = mount('<color-picker-ui format="oklch" value="oklch(0.53 0.01 NaN)"></color-picker-ui>');
    await tick();
    // No warn — NaN is accepted, coerced to 0.
    expect(warn).not.toHaveBeenCalled();
    warn.mockRestore();
  });

  it('accepts `none` (CSS Color L4 powerless)', async () => {
    const warn = vi.spyOn(console, 'warn').mockImplementation(() => {});
    const p = mount('<color-picker-ui format="oklch" value="oklch(0.5 0 none)"></color-picker-ui>');
    await tick();
    expect(warn).not.toHaveBeenCalled();
    warn.mockRestore();
  });

  it('accepts percent on L', async () => {
    const warn = vi.spyOn(console, 'warn').mockImplementation(() => {});
    const p = mount('<color-picker-ui format="oklch" value="oklch(53% 0.05 240)"></color-picker-ui>');
    await tick();
    expect(warn).not.toHaveBeenCalled();
    warn.mockRestore();
  });

  it('accepts hex (regression)', async () => {
    const warn = vi.spyOn(console, 'warn').mockImplementation(() => {});
    const p = mount('<color-picker-ui format="hex" value="#3b82f6"></color-picker-ui>');
    await tick();
    expect(warn).not.toHaveBeenCalled();
    warn.mockRestore();
  });

  it('warns once per element on malformed input', async () => {
    const warn = vi.spyOn(console, 'warn').mockImplementation(() => {});
    const p = mount('<color-picker-ui format="oklch" value="oklch(banana)"></color-picker-ui>');
    await tick();
    // Drive multiple re-parses via setAttribute — should NOT compound the warn count.
    p.setAttribute('value', 'oklch(orange juice)');
    await tick();
    p.setAttribute('value', 'oklch(still broken)');
    await tick();
    expect(warn).toHaveBeenCalledTimes(1);
    expect(warn.mock.calls[0][0]).toMatch(/could not parse value/);
    warn.mockRestore();
  });

  it('two independent pickers each get their own warn budget', async () => {
    const warn = vi.spyOn(console, 'warn').mockImplementation(() => {});
    const p1 = mount('<color-picker-ui format="oklch" value="oklch(broken-1)"></color-picker-ui>');
    const p2 = mount('<color-picker-ui format="oklch" value="oklch(broken-2)"></color-picker-ui>');
    await tick();
    // Two separate instances — each gets their own first-warn.
    expect(warn).toHaveBeenCalledTimes(2);
    warn.mockRestore();
  });
});
