/**
 * Tests for BrandVoiceProfileCard — E5-H1 brand-voice UI.
 *
 * Coverage:
 *  - Null/disabled guards (card renders nothing)
 *  - Profile trait rendering (dl term/definition)
 *  - High-variance mode label
 *  - Toggle: aria-checked, onToggle callback, opt-out notice
 *  - WCAG: role=switch, visible text state (not color-only), focus ring
 *  - Mobile: no layout-breaking assertions (CSS tested via visual review)
 */

import { fireEvent, render, screen } from '@testing-library/react';
import { describe, expect, it, vi } from 'vitest';

import { BrandVoiceProfileCard, type BrandVoiceProfile } from './BrandVoiceProfileCard';

const baseProfile: BrandVoiceProfile = {
  person: '2nd',
  median_sentence_length: 16,
  uses_comparison_tables: true,
  uses_numbered_lists: false,
  tone_adjectives: ['direct', 'practical'],
  sample_size: 42,
  high_variance: false,
};

describe('BrandVoiceProfileCard', () => {
  describe('null / disabled guards', () => {
    it('renders nothing when voiceProfile is null', () => {
      const { container } = render(
        <BrandVoiceProfileCard voiceProfile={null} />,
      );
      expect(container.firstChild).toBeNull();
    });

    it('renders nothing when voiceProfile is undefined', () => {
      const { container } = render(
        <BrandVoiceProfileCard voiceProfile={undefined} />,
      );
      expect(container.firstChild).toBeNull();
    });

    it('renders nothing when enabled=false even with a profile', () => {
      const { container } = render(
        <BrandVoiceProfileCard voiceProfile={baseProfile} enabled={false} />,
      );
      expect(container.firstChild).toBeNull();
    });
  });

  describe('profile trait rendering', () => {
    it('renders the card when a profile is present and enabled', () => {
      render(<BrandVoiceProfileCard voiceProfile={baseProfile} />);
      expect(screen.getByTestId('brand-voice-profile-card')).toBeInTheDocument();
    });

    it('shows "Brand voice matched" title for a normal profile', () => {
      render(<BrandVoiceProfileCard voiceProfile={baseProfile} />);
      expect(screen.getByText('Brand voice matched')).toBeInTheDocument();
    });

    it('shows sample size in the subtitle', () => {
      render(<BrandVoiceProfileCard voiceProfile={baseProfile} />);
      expect(screen.getByText(/42 stable posts/)).toBeInTheDocument();
    });

    it('renders voice person trait', () => {
      render(<BrandVoiceProfileCard voiceProfile={baseProfile} />);
      expect(screen.getByText('Voice')).toBeInTheDocument();
      expect(screen.getByText('2nd person (you)')).toBeInTheDocument();
    });

    it('renders median sentence length trait', () => {
      render(<BrandVoiceProfileCard voiceProfile={baseProfile} />);
      expect(screen.getByText('Avg sentence')).toBeInTheDocument();
      expect(screen.getByText('~16 words')).toBeInTheDocument();
    });

    it('renders tone adjectives trait', () => {
      render(<BrandVoiceProfileCard voiceProfile={baseProfile} />);
      expect(screen.getByText('Tone')).toBeInTheDocument();
      expect(screen.getByText('direct, practical')).toBeInTheDocument();
    });

    it('renders formatting trait for comparison tables', () => {
      render(<BrandVoiceProfileCard voiceProfile={baseProfile} />);
      expect(screen.getByText('Formatting')).toBeInTheDocument();
      expect(screen.getByText('comparison tables')).toBeInTheDocument();
    });

    it('renders both formatting traits when both are true', () => {
      const profile: BrandVoiceProfile = {
        ...baseProfile,
        uses_comparison_tables: true,
        uses_numbered_lists: true,
      };
      render(<BrandVoiceProfileCard voiceProfile={profile} />);
      expect(screen.getByText('comparison tables, numbered lists')).toBeInTheDocument();
    });

    it('does not render formatting row when neither table nor list style is used', () => {
      const profile: BrandVoiceProfile = {
        ...baseProfile,
        uses_comparison_tables: false,
        uses_numbered_lists: false,
      };
      render(<BrandVoiceProfileCard voiceProfile={profile} />);
      expect(screen.queryByText('Formatting')).not.toBeInTheDocument();
    });

    it('handles singular sample size gracefully', () => {
      const profile: BrandVoiceProfile = { ...baseProfile, sample_size: 1 };
      render(<BrandVoiceProfileCard voiceProfile={profile} />);
      // "1 stable post" (not "1 stable posts") — word boundary at end of string.
      expect(screen.getByText(/1 stable post(?!s)/)).toBeInTheDocument();
    });
  });

  describe('high-variance mode', () => {
    it('shows "Voice preservation" title for high-variance profiles', () => {
      const profile: BrandVoiceProfile = { ...baseProfile, high_variance: true };
      render(<BrandVoiceProfileCard voiceProfile={profile} />);
      expect(screen.getByText('Voice preservation')).toBeInTheDocument();
      expect(screen.queryByText('Brand voice matched')).not.toBeInTheDocument();
    });

    it('shows high-variance subtitle copy', () => {
      const profile: BrandVoiceProfile = { ...baseProfile, high_variance: true };
      render(<BrandVoiceProfileCard voiceProfile={profile} />);
      expect(screen.getByText(/high variance/)).toBeInTheDocument();
    });
  });

  describe('toggle (WCAG 1.4.1 + role=switch)', () => {
    it('renders the toggle when onToggle is provided', () => {
      const onToggle = vi.fn();
      render(<BrandVoiceProfileCard voiceProfile={baseProfile} onToggle={onToggle} />);
      expect(screen.getByRole('switch')).toBeInTheDocument();
    });

    it('does not render the toggle when onToggle is absent', () => {
      render(<BrandVoiceProfileCard voiceProfile={baseProfile} />);
      expect(screen.queryByRole('switch')).not.toBeInTheDocument();
    });

    it('has aria-checked=true when applied by default', () => {
      const onToggle = vi.fn();
      render(<BrandVoiceProfileCard voiceProfile={baseProfile} applied={true} onToggle={onToggle} />);
      expect(screen.getByRole('switch')).toHaveAttribute('aria-checked', 'true');
    });

    it('has aria-checked=false when applied=false', () => {
      const onToggle = vi.fn();
      render(<BrandVoiceProfileCard voiceProfile={baseProfile} applied={false} onToggle={onToggle} />);
      expect(screen.getByRole('switch')).toHaveAttribute('aria-checked', 'false');
    });

    it('visible "On" / "Off" text is present so state is not color-only (WCAG 1.4.1)', () => {
      const onToggle = vi.fn();
      render(<BrandVoiceProfileCard voiceProfile={baseProfile} applied={true} onToggle={onToggle} />);
      // The aria-hidden span carries the visible state word (not relied on by SR — SR reads
      // "Brand voice shaping" from aria-label + "on" from aria-checked). Both signals present.
      expect(screen.getByText('On')).toBeInTheDocument();
      // The switch itself has the stable purpose label (not "On"/"Off").
      expect(screen.getByRole('switch')).toHaveAttribute('aria-label', 'Brand voice shaping');
    });

    it('calls onToggle with the next value when clicked', () => {
      const onToggle = vi.fn();
      render(<BrandVoiceProfileCard voiceProfile={baseProfile} applied={true} onToggle={onToggle} />);
      fireEvent.click(screen.getByRole('switch'));
      expect(onToggle).toHaveBeenCalledWith(false);
    });

    it('shows opt-out notice when applied is false', () => {
      const onToggle = vi.fn();
      render(<BrandVoiceProfileCard voiceProfile={baseProfile} applied={false} onToggle={onToggle} />);
      expect(screen.getByTestId('voice-disabled-notice')).toBeInTheDocument();
      expect(screen.getByText(/Brand voice shaping is off/)).toBeInTheDocument();
    });

    it('does not show opt-out notice when applied is true', () => {
      const onToggle = vi.fn();
      render(<BrandVoiceProfileCard voiceProfile={baseProfile} applied={true} onToggle={onToggle} />);
      expect(screen.queryByTestId('voice-disabled-notice')).not.toBeInTheDocument();
    });

    it('toggles applied state locally after click', () => {
      const onToggle = vi.fn();
      render(<BrandVoiceProfileCard voiceProfile={baseProfile} applied={true} onToggle={onToggle} />);
      const toggle = screen.getByRole('switch');
      expect(toggle).toHaveAttribute('aria-checked', 'true');
      fireEvent.click(toggle);
      expect(toggle).toHaveAttribute('aria-checked', 'false');
    });
  });

  describe('null trait fields', () => {
    it('does not render person row when person is null', () => {
      const profile: BrandVoiceProfile = { ...baseProfile, person: null };
      render(<BrandVoiceProfileCard voiceProfile={profile} />);
      expect(screen.queryByText('Voice')).not.toBeInTheDocument();
    });

    it('does not render sentence length row when median_sentence_length is null', () => {
      const profile: BrandVoiceProfile = { ...baseProfile, median_sentence_length: null };
      render(<BrandVoiceProfileCard voiceProfile={profile} />);
      expect(screen.queryByText('Avg sentence')).not.toBeInTheDocument();
    });

    it('does not render tone row when tone_adjectives is empty', () => {
      const profile: BrandVoiceProfile = { ...baseProfile, tone_adjectives: [] };
      render(<BrandVoiceProfileCard voiceProfile={profile} />);
      expect(screen.queryByText('Tone')).not.toBeInTheDocument();
    });
  });

  describe('accessibility structure', () => {
    it('has a heading in the card', () => {
      render(<BrandVoiceProfileCard voiceProfile={baseProfile} />);
      const heading = screen.getByRole('heading', { name: /brand voice/i });
      expect(heading).toBeInTheDocument();
    });

    it('uses a dl for the profile traits (term/definition list for SR)', () => {
      render(<BrandVoiceProfileCard voiceProfile={baseProfile} />);
      const dl = screen.getByTestId('brand-voice-profile-card').querySelector('dl');
      expect(dl).toBeInTheDocument();
    });
  });
});
