import { describe, it, expect, beforeEach } from 'vitest';
import '../../core/element.js';
import './step-progress.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('step-progress-ui', () => {
  beforeEach(() => { document.body.innerHTML = ''; });

  it('registers as a custom element', () => {
    expect(customElements.get('step-progress-ui')).toBeDefined();
  });

  it('sets role=progressbar + aria-value{min,max,now}', () => {
    const el = mount('<step-progress-ui value="3" total="10"></step-progress-ui>');
    expect(el.getAttribute('role')).toBe('progressbar');
    expect(el.getAttribute('aria-valuemin')).toBe('0');
    expect(el.getAttribute('aria-valuemax')).toBe('10');
    expect(el.getAttribute('aria-valuenow')).toBe('3');
  });

  it('auto-mints a caption span + track div', () => {
    const el = mount('<step-progress-ui value="2" total="5" caption="Step 2 of 5"></step-progress-ui>');
    expect(el.querySelector(':scope > [slot="caption"]')).not.toBeNull();
    expect(el.querySelector(':scope > [slot="track"]')).not.toBeNull();
  });

  it('renders one <span> per step in the track', () => {
    const el = mount('<step-progress-ui value="2" total="5"></step-progress-ui>');
    const dashes = el.querySelectorAll(':scope > [slot="track"] > span');
    expect(dashes.length).toBe(5);
  });

  it('marks the first `value` dashes as [data-active]', () => {
    const el = mount('<step-progress-ui value="3" total="5"></step-progress-ui>');
    const dashes = el.querySelectorAll(':scope > [slot="track"] > span');
    expect(dashes[0].hasAttribute('data-active')).toBe(true);
    expect(dashes[1].hasAttribute('data-active')).toBe(true);
    expect(dashes[2].hasAttribute('data-active')).toBe(true);
    expect(dashes[3].hasAttribute('data-active')).toBe(false);
    expect(dashes[4].hasAttribute('data-active')).toBe(false);
  });

  it('renders the caption text in the caption slot', () => {
    const el = mount('<step-progress-ui value="3" total="10" caption="Step 3 of 10"></step-progress-ui>');
    expect(el.querySelector('[slot="caption"]').textContent).toBe('Step 3 of 10');
  });

  it('hides the caption span when caption is empty', () => {
    const el = mount('<step-progress-ui value="2" total="5"></step-progress-ui>');
    expect(el.querySelector('[slot="caption"]').hasAttribute('hidden')).toBe(true);
  });

  it('updates the dash + aria when value changes', async () => {
    const el = mount('<step-progress-ui value="2" total="5"></step-progress-ui>');
    el.value = 4;
    await tick();
    const dashes = el.querySelectorAll(':scope > [slot="track"] > span');
    expect(el.getAttribute('aria-valuenow')).toBe('4');
    expect(dashes[3].hasAttribute('data-active')).toBe(true);
    expect(dashes[4].hasAttribute('data-active')).toBe(false);
  });

  it('grows the dash count when total increases', async () => {
    const el = mount('<step-progress-ui value="2" total="5"></step-progress-ui>');
    expect(el.querySelectorAll('[slot="track"] > span').length).toBe(5);
    el.total = 8;
    await tick();
    expect(el.querySelectorAll('[slot="track"] > span').length).toBe(8);
  });

  it('shrinks the dash count when total decreases', async () => {
    const el = mount('<step-progress-ui value="2" total="8"></step-progress-ui>');
    expect(el.querySelectorAll('[slot="track"] > span').length).toBe(8);
    el.total = 4;
    await tick();
    expect(el.querySelectorAll('[slot="track"] > span').length).toBe(4);
  });

  it('clamps value to [0, total]', () => {
    const el = mount('<step-progress-ui value="20" total="5"></step-progress-ui>');
    const dashes = el.querySelectorAll(':scope > [slot="track"] > span');
    expect(el.getAttribute('aria-valuenow')).toBe('5');
    for (const dash of dashes) {
      expect(dash.hasAttribute('data-active')).toBe(true);
    }
  });

  it('handles value=0 (empty state) — no dashes active', () => {
    const el = mount('<step-progress-ui value="0" total="5"></step-progress-ui>');
    const dashes = el.querySelectorAll(':scope > [slot="track"] > span');
    expect(el.getAttribute('aria-valuenow')).toBe('0');
    for (const dash of dashes) {
      expect(dash.hasAttribute('data-active')).toBe(false);
    }
  });

  it('handles value=total (complete state) — all dashes active', () => {
    const el = mount('<step-progress-ui value="5" total="5" caption="All steps complete"></step-progress-ui>');
    const dashes = el.querySelectorAll(':scope > [slot="track"] > span');
    for (const dash of dashes) {
      expect(dash.hasAttribute('data-active')).toBe(true);
    }
    expect(el.querySelector('[slot="caption"]').textContent).toBe('All steps complete');
  });

  it('survives disconnect without throwing', () => {
    const el = mount('<step-progress-ui value="3" total="10"></step-progress-ui>');
    expect(() => el.remove()).not.toThrow();
  });

  // Regression (audit-wrapper-trap arm 2): WRAPPED consumer [slot="caption"] +
  // [slot="track"] (e.g. via `.map()`/conditional interpolation) must be seen by
  // the absence check so it doesn't MINT duplicates over the consumer's slots.
  it('does NOT mint duplicates when WRAPPED consumer caption + track are present', async () => {
    const el = mount(`<step-progress-ui value="2" total="5"><span style="display:contents" role="presentation"><span slot="caption" data-test="c">Custom</span><div slot="track" data-test="t"></div></span></step-progress-ui>`);
    await tick();
    expect(el.querySelectorAll('[slot="caption"]').length).toBe(1);
    expect(el.querySelectorAll('[slot="track"]').length).toBe(1);
    expect(el.querySelector('[slot="caption"]').dataset.test).toBe('c');
  });
});
