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

import HealthScoreCard from './HealthScoreCard';

// CountUp animates in the real DOM — just render the end value in tests
vi.mock('@/Components/ui/count-up', () => ({
  CountUp: ({ end }: { end: number }) => <span>{end}</span>,
}));

describe('HealthScoreCard', () => {
  describe('empty state (score = null)', () => {
    it('renders "No health score yet" heading', () => {
      render(<HealthScoreCard score={null} previousScore={null} calculatedAt={null} />);
      expect(screen.getByText('No health score yet')).toBeInTheDocument();
    });

    it('renders the explanatory description', () => {
      render(<HealthScoreCard score={null} previousScore={null} calculatedAt={null} />);
      expect(screen.getByText(/Run your first analysis to calculate/i)).toBeInTheDocument();
    });

    it('does not render a score number', () => {
      render(<HealthScoreCard score={null} previousScore={null} calculatedAt={null} />);
      expect(screen.queryByText('/100')).not.toBeInTheDocument();
    });
  });

  describe('with score', () => {
    it('renders the score value and /100 suffix', () => {
      render(<HealthScoreCard score={75} previousScore={null} calculatedAt={null} />);
      expect(screen.getByText('75')).toBeInTheDocument();
      expect(screen.getByText('/100')).toBeInTheDocument();
    });

    it('renders the HealthScoreBadge alongside the score', () => {
      const { container } = render(
        <HealthScoreCard score={75} previousScore={null} calculatedAt={null} />,
      );
      // HealthScoreBadge always renders an aria-label="Health status: …"
      expect(container.querySelector('[aria-label^="Health status:"]')).toBeTruthy();
    });

    it('shows calculatedAt timestamp when provided', () => {
      render(
        <HealthScoreCard score={75} previousScore={null} calculatedAt="2026-01-15T10:00:00Z" />,
      );
      expect(screen.getByText(/Last calculated/i)).toBeInTheDocument();
    });

    it('does not show calculatedAt when null', () => {
      render(<HealthScoreCard score={75} previousScore={null} calculatedAt={null} />);
      expect(screen.queryByText(/Last calculated/i)).not.toBeInTheDocument();
    });
  });

  describe('trend indicator', () => {
    it('shows "No change" when delta is zero', () => {
      render(<HealthScoreCard score={75} previousScore={75} calculatedAt={null} />);
      expect(screen.getByText('No change')).toBeInTheDocument();
    });

    it('shows positive delta with + prefix', () => {
      render(<HealthScoreCard score={80} previousScore={70} calculatedAt={null} />);
      expect(screen.getByText('+10.0 points')).toBeInTheDocument();
    });

    it('shows negative delta with - prefix', () => {
      render(<HealthScoreCard score={65} previousScore={75} calculatedAt={null} />);
      expect(screen.getByText('-10.0 points')).toBeInTheDocument();
    });

    it('does not show trend section when previousScore is null', () => {
      render(<HealthScoreCard score={75} previousScore={null} calculatedAt={null} />);
      expect(screen.queryByText('Since Last Analysis')).not.toBeInTheDocument();
    });

    it('shows "Since Last Analysis" label when trend is visible', () => {
      render(<HealthScoreCard score={80} previousScore={70} calculatedAt={null} />);
      expect(screen.getByText('Since Last Analysis')).toBeInTheDocument();
    });
  });

  describe('accessibility', () => {
    it('has a section title heading', () => {
      render(<HealthScoreCard score={75} previousScore={null} calculatedAt={null} />);
      expect(screen.getByText('Site Health Score')).toBeInTheDocument();
    });

    it('trend direction is conveyed by aria-label, not color alone (improving)', () => {
      render(<HealthScoreCard score={80} previousScore={70} calculatedAt={null} />);
      // The aria-label on the trend div captures the direction textually
      const trendEl = screen.getByLabelText('Up 10.0 points since last analysis');
      expect(trendEl).toBeInTheDocument();
    });

    it('trend direction is conveyed by aria-label, not color alone (declining)', () => {
      render(<HealthScoreCard score={65} previousScore={75} calculatedAt={null} />);
      const trendEl = screen.getByLabelText('Down 10.0 points since last analysis');
      expect(trendEl).toBeInTheDocument();
    });

    it('activity icon is decorative (aria-hidden)', () => {
      const { container } = render(
        <HealthScoreCard score={null} previousScore={null} calculatedAt={null} />,
      );
      // The Activity icon in empty state should be aria-hidden
      const hiddenIcons = container.querySelectorAll('[aria-hidden="true"]');
      expect(hiddenIcons.length).toBeGreaterThan(0);
    });

    it('trend icon is decorative (aria-hidden) — text provides the direction', () => {
      const { container } = render(
        <HealthScoreCard score={80} previousScore={70} calculatedAt={null} />,
      );
      // Both ArrowUp and the numeric span are aria-hidden; the parent div carries aria-label
      const hiddenIcons = container.querySelectorAll('[aria-hidden="true"]');
      expect(hiddenIcons.length).toBeGreaterThan(0);
    });
  });
});
