/**
 * <theme-provider> tests
 *
 * The provider adopts the AdiaUI foundation (a constructable stylesheet) into
 * `document.adoptedStyleSheets` — once, deduped — and renders `display: contents`
 * + `role=presentation`. The real foundation sheet (`web-components.sheet.js`,
 * ~512 KB of LightningCSS output) is mocked here with a 1-rule stub so the test
 * exercises the ELEMENT's contract (adopt-once, dedup, transparency), not the
 * bundle's CSS. Byte-parity of the real sheet is covered by `check:css-bundles-fresh`.
 */

import { describe, it, expect, beforeEach, vi } from 'vitest';

// Stub the heavy foundation sheet — same default-export shape as the generated
// module: a constructSheet() returning a memoized CSSStyleSheet singleton.
vi.mock('../../dist/web-components.sheet.js', () => {
  let sheet = null;
  return {
    default: () => {
      if (typeof CSSStyleSheet === 'undefined') return null;
      if (!sheet) { sheet = new CSSStyleSheet(); sheet.replaceSync('theme-provider{display:contents}'); }
      return sheet;
    },
  };
});

// Stub the opt-in twins — the element dynamic-imports these when theme=/scale= is
// set. We test the attribute contract (sync), not the adopted CSS. (Factories are
// inlined because vi.mock hoists above any shared `const`.)
vi.mock('../../dist/themes.sheet.js', () => ({ default: () => { const s = new CSSStyleSheet(); s.replaceSync(':root{}'); return s; } }));
vi.mock('../../dist/verse.sheet.js', () => ({ default: () => { const s = new CSSStyleSheet(); s.replaceSync(':root{}'); return s; } }));
vi.mock('../../dist/prose.sheet.js', () => ({ default: () => { const s = new CSSStyleSheet(); s.replaceSync(':root{}'); return s; } }));

import '../../core/element.js';
import './theme-provider.js'; // registers the tag + adopts the (mocked) foundation at module-eval

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('<theme-provider>', () => {
  beforeEach(() => { document.body.innerHTML = ''; });

  it('adopts the foundation sheet at import (module-eval side effect)', () => {
    expect(document.adoptedStyleSheets.length).toBeGreaterThanOrEqual(1);
  });

  it('is display:contents + role=presentation on connect', async () => {
    const el = mount('<theme-provider><span>hi</span></theme-provider>');
    await tick();
    expect(el.style.display).toBe('contents');
    expect(el.getAttribute('role')).toBe('presentation');
  });

  it('does not clobber an author-set role', async () => {
    const el = mount('<theme-provider role="group"><span>hi</span></theme-provider>');
    await tick();
    expect(el.getAttribute('role')).toBe('group');
  });

  it('dedupes — N instances adopt the foundation exactly once', async () => {
    const before = document.adoptedStyleSheets.length; // singleton already adopted at import
    mount('<theme-provider></theme-provider>');
    mount('<theme-provider></theme-provider>');
    mount('<theme-provider></theme-provider>');
    await tick();
    expect(document.adoptedStyleSheets.length).toBe(before);
  });

  it('reflects theme= to the [theme] attribute hook', async () => {
    const el = mount('<theme-provider theme="ocean"><span>x</span></theme-provider>');
    await tick();
    expect(el.getAttribute('theme')).toBe('ocean');
  });

  it('scale="verse" maps to the [verse] register attribute', async () => {
    const el = mount('<theme-provider scale="verse"><span>x</span></theme-provider>');
    await tick();
    expect(el.hasAttribute('verse')).toBe(true);
    expect(el.hasAttribute('prose')).toBe(false);
  });

  it('scale="prose" maps to the [prose] register attribute', async () => {
    const el = mount('<theme-provider scale="prose"><span>x</span></theme-provider>');
    await tick();
    expect(el.hasAttribute('prose')).toBe(true);
    expect(el.hasAttribute('verse')).toBe(false);
  });
});
