// packages/web/src/components/ui/__tests__/Mascot.test.tsx
import { describe, it, expect } from 'vitest';
import { render } from '@testing-library/react';
import { Mascot } from '../Mascot';

describe('Mascot', () => {
  it('renders an SVG with aria-hidden and presentation role', () => {
    const { container } = render(<Mascot state="idle" />);
    const wrapper = container.firstElementChild as HTMLElement;
    expect(wrapper.getAttribute('role')).toBe('presentation');
    const svg = wrapper.querySelector('svg');
    expect(svg).toBeTruthy();
    expect(svg!.getAttribute('aria-hidden')).toBe('true');
  });

  it('applies idle palette gradient stops', () => {
    const { container } = render(<Mascot state="idle" />);
    const stops = container.querySelectorAll('stop');
    const colors = Array.from(stops).map(s => s.getAttribute('stop-color'));
    expect(colors).toContain('#c8f0de');
    expect(colors).toContain('#6dbf96');
  });

  it('applies sleeping palette gradient stops', () => {
    const { container } = render(<Mascot state="sleeping" />);
    const stops = container.querySelectorAll('stop');
    const colors = Array.from(stops).map(s => s.getAttribute('stop-color'));
    expect(colors).toContain('#ddd4f0');
    expect(colors).toContain('#a898cc');
  });

  it('applies excited palette gradient stops', () => {
    const { container } = render(<Mascot state="excited" />);
    const stops = container.querySelectorAll('stop');
    const colors = Array.from(stops).map(s => s.getAttribute('stop-color'));
    expect(colors).toContain('#fde0c8');
    expect(colors).toContain('#e8a870');
  });

  it('applies lonely palette gradient stops', () => {
    const { container } = render(<Mascot state="lonely" />);
    const stops = container.querySelectorAll('stop');
    const colors = Array.from(stops).map(s => s.getAttribute('stop-color'));
    expect(colors).toContain('#c0dced');
    expect(colors).toContain('#78aec8');
  });

  it('renders upright viewBox for idle state', () => {
    const { container } = render(<Mascot state="idle" />);
    const svg = container.querySelector('svg');
    expect(svg!.getAttribute('viewBox')).toBe('0 0 200 200');
  });

  it('renders wide viewBox for sleeping state', () => {
    const { container } = render(<Mascot state="sleeping" />);
    const svg = container.querySelector('svg');
    expect(svg!.getAttribute('viewBox')).toBe('0 0 220 130');
  });

  it('renders closed-eye arcs (path elements) for sleeping state', () => {
    const { container } = render(<Mascot state="sleeping" />);
    const eyeWhites = container.querySelectorAll('[data-eye="white"]');
    expect(eyeWhites.length).toBe(0);
    const closedEyes = container.querySelectorAll('[data-eye="closed"]');
    expect(closedEyes.length).toBe(2);
  });

  it('renders open eyes (ellipses) for non-sleeping states', () => {
    const { container } = render(<Mascot state="idle" />);
    const eyeWhites = container.querySelectorAll('[data-eye="white"]');
    expect(eyeWhites.length).toBe(2);
  });

  it('renders a z-particle container for sleeping state', () => {
    const { container } = render(<Mascot state="sleeping" />);
    const zBox = container.querySelector('[data-mascot="z-container"]');
    expect(zBox).toBeTruthy();
  });

  it('does not render z-particle container for non-sleeping states', () => {
    const { container } = render(<Mascot state="idle" />);
    const zBox = container.querySelector('[data-mascot="z-container"]');
    expect(zBox).toBeFalsy();
  });

  it('renders a ground shadow', () => {
    const { container } = render(<Mascot state="idle" />);
    const shadow = container.querySelector('[data-mascot="shadow"]');
    expect(shadow).toBeTruthy();
  });

  it('applies custom className replacing default size', () => {
    const { container } = render(<Mascot state="idle" className="w-48 h-48" />);
    const wrapper = container.firstElementChild as HTMLElement;
    expect(wrapper.className).toContain('w-48');
    expect(wrapper.className).toContain('h-48');
    // Custom className replaces default w-32 h-32 to avoid Tailwind conflicts
    expect(wrapper.className).not.toContain('w-32');
  });

  it('uses default w-32 h-32 when no className provided', () => {
    const { container } = render(<Mascot state="idle" />);
    const wrapper = container.firstElementChild as HTMLElement;
    expect(wrapper.className).toContain('w-32');
    expect(wrapper.className).toContain('h-32');
  });

  it('renders the sleeping mouth ellipse', () => {
    const { container } = render(<Mascot state="sleeping" />);
    const mouth = container.querySelector('[data-mascot="mouth"]');
    expect(mouth).toBeTruthy();
    expect(mouth!.tagName.toLowerCase()).toBe('ellipse');
  });

  it('renders the upright mouth as a path for idle', () => {
    const { container } = render(<Mascot state="idle" />);
    const mouth = container.querySelector('[data-mascot="mouth"]');
    expect(mouth).toBeTruthy();
    expect(mouth!.tagName.toLowerCase()).toBe('path');
  });

  describe('Mascot animation lifecycle', () => {
    it('renders without crashing when element.animate is unavailable (jsdom)', () => {
      expect(() => render(<Mascot state="idle" />)).not.toThrow();
    });

    it('renders without crashing for each state', () => {
      for (const state of ['idle', 'sleeping', 'excited', 'lonely'] as const) {
        const { unmount } = render(<Mascot state={state} />);
        unmount();
      }
    });
  });
});
