// @vitest-environment happy-dom
import { describe, it, expect, vi } from 'vitest';
import { render, screen, fireEvent } from '@testing-library/react';
import { LoadingSpinner } from './LoadingSpinner.js';
import { LoadingSkeleton } from './LoadingSkeleton.js';
import { EmptyState } from './EmptyState.js';
import { PageHeader } from './PageHeader.js';
import { ErrorPage } from './ErrorPage.js';
import { NotFoundPage } from './NotFoundPage.js';

describe('LoadingSpinner', () => {
  it('renders with default size', () => {
    render(<LoadingSpinner />);
    const status = screen.getByRole('status');
    expect(status).toBeDefined();
    expect(status.className).toContain('w-8 h-8');
  });

  it('renders with small size', () => {
    render(<LoadingSpinner size="sm" />);
    const status = screen.getByRole('status');
    expect(status.className).toContain('w-4 h-4');
  });

  it('renders with large size', () => {
    render(<LoadingSpinner size="lg" />);
    const status = screen.getByRole('status');
    expect(status.className).toContain('w-12 h-12');
  });

  it('applies custom className', () => {
    render(<LoadingSpinner className="mt-4" />);
    const status = screen.getByRole('status');
    expect(status.className).toContain('mt-4');
  });

  it('renders SVG spinner element', () => {
    render(<LoadingSpinner />);
    const svg = screen.getByRole('status').querySelector('svg');
    expect(svg).toBeDefined();
    expect(svg!.classList.contains('animate-spin')).toBe(true);
  });
});

describe('LoadingSkeleton', () => {
  it('renders default 3 rows', () => {
    render(<LoadingSkeleton />);
    const container = screen.getByRole('status');
    const rows = container.querySelectorAll('.animate-pulse');
    expect(rows.length).toBe(3);
  });

  it('renders custom number of rows', () => {
    render(<LoadingSkeleton rows={5} />);
    const container = screen.getByRole('status');
    const rows = container.querySelectorAll('.animate-pulse');
    expect(rows.length).toBe(5);
  });

  it('applies custom className', () => {
    render(<LoadingSkeleton className="my-8" />);
    const container = screen.getByRole('status');
    expect(container.className).toContain('my-8');
  });

  it('renders pulse-animated skeleton rows', () => {
    render(<LoadingSkeleton rows={1} />);
    const row = screen.getByRole('status').querySelector('.animate-pulse');
    expect(row).toBeDefined();
    expect(row!.classList.contains('rounded')).toBe(true);
  });
});

describe('EmptyState', () => {
  it('renders title and description', () => {
    render(<EmptyState title="No items" description="Create your first item." />);
    expect(screen.getByText('No items')).toBeDefined();
    expect(screen.getByText('Create your first item.')).toBeDefined();
  });

  it('renders icon when provided', () => {
    render(
      <EmptyState
        title="No items"
        description="Create one."
        icon={<span data-testid="icon">X</span>}
      />
    );
    expect(screen.getByTestId('icon')).toBeDefined();
  });

  it('does not render icon container when not provided', () => {
    const { container } = render(<EmptyState title="No items" description="Create one." />);
    const iconWrapper = container.querySelector('.w-16.h-16');
    expect(iconWrapper).toBeNull();
  });

  it('renders action button and handles click', () => {
    const onClick = vi.fn();
    render(
      <EmptyState
        title="No items"
        description="Create one."
        action={{ label: 'Create', onClick }}
      />
    );
    const button = screen.getByText('Create');
    expect(button).toBeDefined();
    fireEvent.click(button);
    expect(onClick).toHaveBeenCalledOnce();
  });

  it('does not render action button when not provided', () => {
    const { container } = render(<EmptyState title="No items" description="Create one." />);
    const buttons = container.querySelectorAll('button');
    expect(buttons.length).toBe(0);
  });

  it('renders with theme-aware structure', () => {
    const { container } = render(<EmptyState title="Test" description="Desc" />);
    const heading = container.querySelector('h3');
    expect(heading).toBeDefined();
    expect(heading!.textContent).toBe('Test');
    const desc = container.querySelector('p');
    expect(desc).toBeDefined();
    expect(desc!.textContent).toBe('Desc');
  });
});

describe('PageHeader', () => {
  it('renders title', () => {
    render(<PageHeader title="Dashboard" />);
    expect(screen.getByText('Dashboard')).toBeDefined();
  });

  it('renders breadcrumbs', () => {
    render(
      <PageHeader title="Users" breadcrumbs={[{ label: 'Home', href: '/' }, { label: 'Users' }]} />
    );
    expect(screen.getByText('Home')).toBeDefined();
    expect(screen.getByLabelText('Breadcrumb')).toBeDefined();
  });

  it('renders breadcrumb links with href', () => {
    render(
      <PageHeader
        title="Detail"
        breadcrumbs={[{ label: 'Home', href: '/' }, { label: 'Detail' }]}
      />
    );
    const link = screen.getByText('Home');
    expect(link.tagName).toBe('A');
    expect(link.getAttribute('href')).toBe('/');
  });

  it('renders breadcrumb text without href', () => {
    render(<PageHeader title="Detail" breadcrumbs={[{ label: 'Current' }]} />);
    const text = screen.getByText('Current');
    expect(text.tagName).toBe('SPAN');
  });

  it('renders actions', () => {
    render(<PageHeader title="Test" actions={<button data-testid="action-btn">Action</button>} />);
    expect(screen.getByTestId('action-btn')).toBeDefined();
  });

  it('does not render breadcrumb nav when empty', () => {
    const { container } = render(<PageHeader title="Simple" />);
    const nav = container.querySelector('nav');
    expect(nav).toBeNull();
  });
});

describe('ErrorPage', () => {
  it('renders with default props', () => {
    render(<ErrorPage />);
    expect(screen.getByText('Something went wrong')).toBeDefined();
    expect(screen.getByText('An unexpected error occurred. Please try again.')).toBeDefined();
  });

  it('renders custom title and message', () => {
    render(<ErrorPage title="Server Error" message="The server is down." />);
    expect(screen.getByText('Server Error')).toBeDefined();
    expect(screen.getByText('The server is down.')).toBeDefined();
  });

  it('renders retry button and handles click', () => {
    const onRetry = vi.fn();
    render(<ErrorPage onRetry={onRetry} />);
    const button = screen.getByText('Try Again');
    expect(button).toBeDefined();
    fireEvent.click(button);
    expect(onRetry).toHaveBeenCalledOnce();
  });

  it('does not render retry button when not provided', () => {
    const { container } = render(<ErrorPage />);
    const buttons = container.querySelectorAll('button');
    expect(buttons.length).toBe(0);
  });

  it('renders error icon and semantic structure', () => {
    const { container } = render(<ErrorPage />);
    const iconContainer = container.querySelector('.w-16');
    expect(iconContainer).toBeDefined();
    const svg = iconContainer!.querySelector('svg');
    expect(svg).toBeDefined();
    const heading = container.querySelector('h2');
    expect(heading).toBeDefined();
    expect(heading!.textContent).toBe('Something went wrong');
  });
});

describe('NotFoundPage', () => {
  it('renders with default props', () => {
    render(<NotFoundPage />);
    expect(screen.getByText('404')).toBeDefined();
    expect(screen.getByText('Page not found')).toBeDefined();
  });

  it('renders custom status code', () => {
    render(<NotFoundPage statusCode="403" title="Forbidden" />);
    expect(screen.getByText('403')).toBeDefined();
    expect(screen.getByText('Forbidden')).toBeDefined();
  });

  it('renders back button with onClick', () => {
    const onBack = vi.fn();
    render(<NotFoundPage onBack={onBack} />);
    const button = screen.getByText('Go Back');
    fireEvent.click(button);
    expect(onBack).toHaveBeenCalledOnce();
  });

  it('renders back link with href', () => {
    render(<NotFoundPage backHref="/" backLabel="Go Home" />);
    const link = screen.getByText('Go Home');
    expect(link.tagName).toBe('A');
    expect(link.getAttribute('href')).toBe('/');
  });

  it('does not render button when neither onBack nor backHref provided', () => {
    const { container } = render(<NotFoundPage />);
    const buttons = container.querySelectorAll('button');
    const links = container.querySelectorAll('a');
    expect(buttons.length).toBe(0);
    expect(links.length).toBe(0);
  });

  it('custom backLabel is used', () => {
    render(<NotFoundPage onBack={() => {}} backLabel="Return" />);
    expect(screen.getByText('Return')).toBeDefined();
  });
});
