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

function setValue(host, value) {
  host.value = value;
  host.dispatchEvent(new Event('input'));
}

describe('validation', () => {
  beforeEach(resetDOM);

  it('required: empty value is invalid', () => {
    const host = mountHost('input', { 'data-validate': 'required' });
    connectTrait(validation, host);
    setValue(host, '');
    expect(host.hasAttribute('data-validation-invalid')).toBe(true);
    expect(host.getAttribute('data-validation-message')).toBe('This field is required');
  });

  it('required: non-empty value is valid', () => {
    const host = mountHost('input', { 'data-validate': 'required' });
    connectTrait(validation, host);
    setValue(host, 'hello');
    expect(host.hasAttribute('data-validation-valid')).toBe(true);
    expect(host.hasAttribute('data-validation-invalid')).toBe(false);
  });

  it('email: rejects malformed input', () => {
    const host = mountHost('input', { 'data-validate': 'email' });
    connectTrait(validation, host);
    setValue(host, 'not-an-email');
    expect(host.getAttribute('data-validation-message')).toBe('Invalid email address');
  });

  it('email: accepts well-formed addresses', () => {
    const host = mountHost('input', { 'data-validate': 'email' });
    connectTrait(validation, host);
    setValue(host, 'user@example.com');
    expect(host.hasAttribute('data-validation-valid')).toBe(true);
  });

  it('minlength: enforces minimum character count', () => {
    const host = mountHost('input', { 'data-validate': 'minlength:5' });
    connectTrait(validation, host);
    setValue(host, 'hi');
    expect(host.getAttribute('data-validation-message')).toBe('Minimum length is 5');
    setValue(host, 'hello!');
    expect(host.hasAttribute('data-validation-valid')).toBe(true);
  });

  it('pattern: enforces regex match', () => {
    const host = mountHost('input', { 'data-validate': 'pattern:^[A-Z]+$' });
    connectTrait(validation, host);
    setValue(host, 'lower');
    expect(host.hasAttribute('data-validation-invalid')).toBe(true);
    setValue(host, 'UPPER');
    expect(host.hasAttribute('data-validation-valid')).toBe(true);
  });

  it('combined rules: required + email both checked', () => {
    const host = mountHost('input', { 'data-validate': 'required, email' });
    connectTrait(validation, host);
    const spy = spyEvent(host, 'validated');
    setValue(host, '');
    expect(spy.last.errors).toContain('This field is required');
    setValue(host, 'bad');
    expect(spy.last.errors).toContain('Invalid email address');
    setValue(host, 'ok@example.com');
    expect(spy.last.valid).toBe(true);
  });

  it('dispatches "validated" event with detail.valid and detail.errors', () => {
    const host = mountHost('input', { 'data-validate': 'required' });
    connectTrait(validation, host);
    const spy = spyEvent(host, 'validated');
    setValue(host, '');
    expect(spy.count).toBe(1);
    expect(spy.last.valid).toBe(false);
    expect(spy.last.errors.length).toBe(1);
  });

  it('disconnect clears all validation attributes', () => {
    const host = mountHost('input', { 'data-validate': 'required' });
    const inst = connectTrait(validation, host);
    setValue(host, '');
    expect(host.hasAttribute('data-validation-invalid')).toBe(true);
    inst.disconnect(host);
    expect(host.hasAttribute('data-validation-invalid')).toBe(false);
    expect(host.hasAttribute('data-validation-valid')).toBe(false);
    expect(host.hasAttribute('data-validation-message')).toBe(false);
  });
});
