import { describe, it, expect, beforeEach } from 'vitest';
import { successCheckmark } from './success-checkmark.js';
import { mountHost, connectTrait, spyEvent, resetDOM, wait } from '../test-helpers.js';

// Helper: query the SVG that the trait stamps. As of the overflow:hidden
// fix, the SVG renders at body level (position: fixed) so it can't be
// clipped by the host's ancestors — query document.body, not the host.
const findSvg = () => document.body.querySelector('svg');

describe('success-checkmark', () => {
  beforeEach(resetDOM);

  it('schema declares animation-feedback category', () => {
    expect(successCheckmark.schema.category).toBe('animation-feedback');
    expect(successCheckmark.schema.events).toContain('success-checkmark-done');
    expect(successCheckmark.schema.attributes).toContain('data-success-checkmark-active');
  });

  it('connect → disconnect leaves no managed attribute', () => {
    const host = mountHost();
    const inst = connectTrait(successCheckmark, host);
    inst.disconnect(host);
    expect(host.hasAttribute('data-success-checkmark-active')).toBe(false);
  });

  it('stamps an SVG on validated event with detail.valid === true', () => {
    const host = mountHost();
    connectTrait(successCheckmark, host);

    host.dispatchEvent(new CustomEvent('validated', {
      detail: { valid: true, errors: [] },
    }));

    expect(host.hasAttribute('data-success-checkmark-active')).toBe(true);
    const svg = findSvg();
    expect(svg).not.toBeNull();
    expect(svg.querySelector('path')).not.toBeNull();
  });

  it('does not stamp on validated event with detail.valid === false', () => {
    const host = mountHost();
    connectTrait(successCheckmark, host);

    host.dispatchEvent(new CustomEvent('validated', {
      detail: { valid: false, errors: ['nope'] },
    }));

    expect(host.hasAttribute('data-success-checkmark-active')).toBe(false);
    expect(findSvg()).toBeNull();
  });

  it('fires on data-validation-valid (false → true)', async () => {
    const host = mountHost();
    connectTrait(successCheckmark, host);

    host.setAttribute('data-validation-valid', '');
    await wait(0);
    expect(host.hasAttribute('data-success-checkmark-active')).toBe(true);
    expect(findSvg()).not.toBeNull();
  });

  it('respects data-success-checkmark-trigger attribute toggle', async () => {
    const host = mountHost();
    connectTrait(successCheckmark, host);

    host.setAttribute('data-success-checkmark-trigger', '');
    await wait(0);
    expect(findSvg()).not.toBeNull();
  });

  it('renders position: fixed at viewport coordinates (no longer clipped by host overflow)', () => {
    const host = mountHost();
    connectTrait(successCheckmark, host);

    host.dispatchEvent(new CustomEvent('validated', {
      detail: { valid: true, errors: [] },
    }));

    const svg = findSvg();
    expect(svg).not.toBeNull();
    // Body-level rendering with position: fixed escapes any
    // overflow:hidden ancestor that the host might be inside.
    expect(svg.style.position).toBe('fixed');
    expect(svg.parentElement).toBe(document.body);
  });

  it('removes the SVG and fires success-checkmark-done after the visible+fade window', async () => {
    const host = mountHost();
    connectTrait(successCheckmark, host);
    const spy = spyEvent(host, 'success-checkmark-done');

    host.dispatchEvent(new CustomEvent('validated', { detail: { valid: true } }));
    expect(findSvg()).not.toBeNull();

    // 1500ms hold + 300ms fade = ~1800ms; give a small grace window.
    await wait(1900);
    expect(findSvg()).toBeNull();
    expect(spy.count).toBe(1);
    expect(host.hasAttribute('data-success-checkmark-active')).toBe(false);
  });

  it('disconnect removes any in-flight SVG', () => {
    const host = mountHost();
    const inst = connectTrait(successCheckmark, host);
    host.dispatchEvent(new CustomEvent('validated', { detail: { valid: true } }));
    expect(findSvg()).not.toBeNull();

    inst.disconnect(host);
    expect(findSvg()).toBeNull();
    expect(host.hasAttribute('data-success-checkmark-active')).toBe(false);
  });

  it('does not mutate host.style.position (body-level rendering means the host needs no positioning context)', () => {
    const host = mountHost();
    const before = host.style.position;
    connectTrait(successCheckmark, host);
    host.dispatchEvent(new CustomEvent('validated', { detail: { valid: true } }));
    expect(host.style.position).toBe(before);
  });
});
