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

import CannibalizationIndex from './Index';

vi.mock('@inertiajs/react', async () => {
  const actual = await vi.importActual('@inertiajs/react');
  return {
    ...actual,
    Head: ({ title }: { title: string }) => <title>{title}</title>,
    Link: ({
      children,
      href,
      className,
    }: {
      children: React.ReactNode;
      href: string;
      className?: string;
    }) => (
      <a href={href} className={className}>
        {children}
      </a>
    ),
    router: { reload: vi.fn() },
    usePage: () => ({
      props: {},
    }),
  };
});

vi.mock('@/Layouts/DashboardLayout', () => ({
  default: ({ children }: { children: React.ReactNode }) => (
    <div data-testid="dashboard-layout">{children}</div>
  ),
}));

vi.mock('@/Components/Navigation/SiteNav', () => ({
  default: () => <div data-testid="site-nav" />,
}));

vi.mock('@/Components/Shared/InertiaPagination', () => ({
  default: () => <div data-testid="pagination" />,
}));

vi.mock('@/Components/ui/empty-state', () => ({
  EmptyState: ({
    title,
    description,
    action,
  }: {
    title: string;
    description: string;
    action?: React.ReactNode;
  }) => (
    <div data-testid="empty-state">
      {title}: {description}
      {action}
    </div>
  ),
}));

vi.mock('@/Components/ui/button', () => ({
  Button: ({
    children,
    onClick,
    asChild,
  }: {
    children: React.ReactNode;
    onClick?: () => void;
    asChild?: boolean;
  }) => (asChild ? <>{children}</> : <button onClick={onClick}>{children}</button>),
}));

vi.mock('@/Components/ui/badge', () => ({
  Badge: ({ children, variant }: { children: React.ReactNode; variant?: string }) => (
    <span data-testid="badge" data-variant={variant}>
      {children}
    </span>
  ),
}));

vi.mock('@/Components/ui/card', () => ({
  Card: ({ children, className }: { children: React.ReactNode; className?: string }) => (
    <div data-testid="card" className={className}>
      {children}
    </div>
  ),
  CardHeader: ({ children }: { children: React.ReactNode }) => (
    <div data-testid="card-header">{children}</div>
  ),
  CardTitle: ({ children }: { children: React.ReactNode }) => (
    <div data-testid="card-title">{children}</div>
  ),
  CardDescription: ({ children }: { children: React.ReactNode }) => (
    <div data-testid="card-description">{children}</div>
  ),
  CardContent: ({ children }: { children: React.ReactNode }) => (
    <div data-testid="card-content">{children}</div>
  ),
}));

const emptyProps = {
  site: { id: 1, name: 'Test Site', domain: 'https://test.com' },
  cannibalizationRun: null,
  cases: [],
  filters: { status: null, min_impact: null },
  counts: { total: 0, open: 0, closed: 0, dismissed: 0, high_impact: 0 },
};

const withCasesProps = {
  ...emptyProps,
  cannibalizationRun: { id: 1, status: 'completed', completed_at: '2026-01-15' },
  cases: {
    data: [
      {
        id: 1,
        query_cluster: 'best laptops 2026',
        competing_pages_count: 3,
        lead_volatility_score: 0.8,
        impact_score: 85.5,
        confidence_score: 72.3,
        primary_page_url: null,
        status: 'open',
        lifecycle_status: 'pending',
        dismissed_at: null,
        created_at: '2026-01-15',
      },
      {
        id: 2,
        query_cluster: 'laptop reviews',
        competing_pages_count: 2,
        lead_volatility_score: 0.3,
        impact_score: 45.0,
        confidence_score: 60.0,
        primary_page_url: '/laptop-guide',
        status: 'closed',
        lifecycle_status: 'resolved',
        dismissed_at: null,
        created_at: '2026-01-15',
      },
    ],
    links: [
      { url: null, label: '&laquo; Previous', active: false },
      { url: '/cannibalization?page=1', label: '1', active: true },
      { url: null, label: 'Next &raquo;', active: false },
    ],
    current_page: 1,
    last_page: 1,
  },
  counts: { total: 2, open: 1, closed: 1, dismissed: 0, high_impact: 1 },
};

describe('Cannibalization/Index', () => {
  beforeEach(() => {
    vi.clearAllMocks();
    vi.stubGlobal(
      'route',
      vi.fn((...args: string[]) => `/mock-route/${args[0]}`),
    );
  });

  // ============================================
  // Rendering tests
  // ============================================

  describe('rendering', () => {
    it('renders page title with site name', () => {
      render(<CannibalizationIndex {...emptyProps} />);

      expect(document.querySelector('title')).toHaveTextContent(
        'Test Site - Cannibalization Cases',
      );
    });

    it('renders heading "Cannibalization Cases"', () => {
      render(<CannibalizationIndex {...emptyProps} />);

      expect(screen.getByRole('heading', { name: 'Cannibalization Cases' })).toBeInTheDocument();
    });

    it('renders SiteNav component', () => {
      render(<CannibalizationIndex {...emptyProps} />);

      expect(screen.getByTestId('site-nav')).toBeInTheDocument();
    });
  });

  // ============================================
  // Empty state tests
  // ============================================

  describe('empty states', () => {
    it('shows empty state when no cannibalization run', () => {
      render(<CannibalizationIndex {...emptyProps} />);

      const emptyState = screen.getByTestId('empty-state');
      expect(emptyState).toHaveTextContent('No cannibalization analysis');
      expect(emptyState).toHaveTextContent(
        'Run a cannibalization detection to identify competing pages',
      );

      const link = screen.getByRole('link', { name: /go to analysis/i });
      expect(link).toBeInTheDocument();
    });

    it('shows empty state when run completed but no cases found', () => {
      render(
        <CannibalizationIndex
          {...emptyProps}
          cannibalizationRun={{ id: 1, status: 'completed', completed_at: '2026-01-15' }}
        />,
      );

      const emptyState = screen.getByTestId('empty-state');
      expect(emptyState).toHaveTextContent('No cannibalization cases found');
      expect(emptyState).toHaveTextContent('No competing pages were detected');
    });
  });

  // ============================================
  // Cases list tests
  // ============================================

  describe('cases list', () => {
    it('renders case cards when cases exist', () => {
      render(<CannibalizationIndex {...withCasesProps} />);

      const cards = screen.getAllByTestId('card');
      expect(cards).toHaveLength(2);

      expect(screen.getByText('best laptops 2026')).toBeInTheDocument();
      expect(screen.getByText('laptop reviews')).toBeInTheDocument();
    });

    it('displays competing pages count for each case', () => {
      render(<CannibalizationIndex {...withCasesProps} />);

      expect(screen.getByText('3 competing pages')).toBeInTheDocument();
      expect(screen.getByText('2 competing pages')).toBeInTheDocument();
    });

    it('displays impact and confidence scores', () => {
      render(<CannibalizationIndex {...withCasesProps} />);

      expect(screen.getByText('85.5')).toBeInTheDocument();
      expect(screen.getByText('72.3')).toBeInTheDocument();
      expect(screen.getByText('45.0')).toBeInTheDocument();
      expect(screen.getByText('60.0')).toBeInTheDocument();
    });

    it('displays case status', () => {
      render(<CannibalizationIndex {...withCasesProps} />);

      const openStatuses = screen.getAllByText('open', { exact: false });
      const closedStatuses = screen.getAllByText('closed', { exact: false });

      // Should find both the filter link and the case status
      expect(openStatuses.length).toBeGreaterThan(0);
      expect(closedStatuses.length).toBeGreaterThan(0);
    });

    it('shows primary page URL when set', () => {
      render(<CannibalizationIndex {...withCasesProps} />);

      expect(screen.getByText('/laptop-guide')).toBeInTheDocument();
    });

    it('shows View Details button for each case', () => {
      render(<CannibalizationIndex {...withCasesProps} />);

      const viewButtons = screen.getAllByRole('link', { name: /view details/i });
      expect(viewButtons).toHaveLength(2);
    });

    it('renders pagination when cases exist', () => {
      render(<CannibalizationIndex {...withCasesProps} />);

      expect(screen.getByTestId('pagination')).toBeInTheDocument();
    });
  });

  // ============================================
  // Status filter tests
  // ============================================

  describe('status filter', () => {
    it('renders status filter when cases exist', () => {
      render(<CannibalizationIndex {...withCasesProps} />);

      expect(screen.getByRole('link', { name: 'All (2)' })).toBeInTheDocument();
      expect(screen.getByRole('link', { name: 'Open (1)' })).toBeInTheDocument();
      expect(screen.getByRole('link', { name: 'Closed (1)' })).toBeInTheDocument();
      expect(screen.getByRole('link', { name: 'Dismissed (0)' })).toBeInTheDocument();
    });

    it('does not render status filter when no cases', () => {
      render(<CannibalizationIndex {...emptyProps} />);

      expect(screen.queryByRole('link', { name: /All \(\d+\)/ })).not.toBeInTheDocument();
    });

    it('highlights current filter', () => {
      const propsWithFilter = {
        ...withCasesProps,
        filters: { status: 'open', min_impact: null },
      };

      render(<CannibalizationIndex {...propsWithFilter} />);

      const openFilter = screen.getByRole('link', { name: 'Open (1)' });
      expect(openFilter).toHaveClass('bg-primary', 'text-primary-foreground');
    });
  });

  // ============================================
  // Impact badge tests
  // ============================================

  describe('impact badges', () => {
    it('renders high impact badge for score >= 70', () => {
      render(<CannibalizationIndex {...withCasesProps} />);

      const badges = screen.getAllByTestId('badge');
      const highImpactBadge = badges.find(
        (badge) =>
          badge.getAttribute('data-variant') === 'destructive' && badge.textContent === 'High',
      );

      expect(highImpactBadge).toBeInTheDocument();
    });

    it('renders medium impact badge for score >= 40 and < 70', () => {
      render(<CannibalizationIndex {...withCasesProps} />);

      const badges = screen.getAllByTestId('badge');
      const mediumImpactBadge = badges.find(
        (badge) =>
          badge.getAttribute('data-variant') === 'default' && badge.textContent === 'Medium',
      );

      expect(mediumImpactBadge).toBeInTheDocument();
    });

    it('renders low impact badge for score < 40', () => {
      const propsWithLowImpact = {
        ...withCasesProps,
        cases: {
          ...withCasesProps.cases,
          data: [
            {
              ...withCasesProps.cases.data[0],
              impact_score: 25.0,
            },
          ],
        },
      };

      render(<CannibalizationIndex {...propsWithLowImpact} />);

      const badges = screen.getAllByTestId('badge');
      const lowImpactBadge = badges.find(
        (badge) =>
          badge.getAttribute('data-variant') === 'secondary' && badge.textContent === 'Low',
      );

      expect(lowImpactBadge).toBeInTheDocument();
    });
  });

  // ============================================
  // Volatility badge tests
  // ============================================

  describe('volatility badges', () => {
    it('renders high volatility badge for score >= 0.7', () => {
      render(<CannibalizationIndex {...withCasesProps} />);

      const badges = screen.getAllByTestId('badge');
      const highVolatilityBadge = badges.find(
        (badge) =>
          badge.getAttribute('data-variant') === 'destructive' &&
          badge.textContent === 'High Volatility',
      );

      expect(highVolatilityBadge).toBeInTheDocument();
    });

    it('renders medium volatility badge for score >= 0.4 and < 0.7', () => {
      const propsWithMediumVolatility = {
        ...withCasesProps,
        cases: {
          ...withCasesProps.cases,
          data: [
            {
              ...withCasesProps.cases.data[0],
              lead_volatility_score: 0.5,
            },
          ],
        },
      };

      render(<CannibalizationIndex {...propsWithMediumVolatility} />);

      const badges = screen.getAllByTestId('badge');
      const mediumVolatilityBadge = badges.find(
        (badge) =>
          badge.getAttribute('data-variant') === 'default' &&
          badge.textContent === 'Medium Volatility',
      );

      expect(mediumVolatilityBadge).toBeInTheDocument();
    });

    it('renders low volatility badge for score < 0.4', () => {
      render(<CannibalizationIndex {...withCasesProps} />);

      const badges = screen.getAllByTestId('badge');
      const lowVolatilityBadge = badges.find(
        (badge) =>
          badge.getAttribute('data-variant') === 'secondary' &&
          badge.textContent === 'Low Volatility',
      );

      expect(lowVolatilityBadge).toBeInTheDocument();
    });
  });

  // ============================================
  // Props structure tests
  // ============================================

  describe('props structure handling', () => {
    it('handles paginated cases structure', () => {
      render(<CannibalizationIndex {...withCasesProps} />);

      expect(screen.getAllByTestId('card')).toHaveLength(2);
    });

    it('handles array cases structure', () => {
      const propsWithArrayCases = {
        ...withCasesProps,
        cases: withCasesProps.cases.data,
      };

      render(<CannibalizationIndex {...propsWithArrayCases} />);

      expect(screen.getAllByTestId('card')).toHaveLength(2);
    });

    it('handles pagination prop separately', () => {
      const propsWithSeparatePagination = {
        ...withCasesProps,
        cases: withCasesProps.cases.data,
        pagination: {
          current_page: 1,
          last_page: 3,
          per_page: 25,
          total: 75,
        },
      };

      render(<CannibalizationIndex {...propsWithSeparatePagination} />);

      expect(screen.getAllByTestId('card')).toHaveLength(2);
    });
  });

  // ============================================
  // Layout tests
  // ============================================

  describe('layout', () => {
    it('assigns DashboardLayout as layout', () => {
      expect(CannibalizationIndex.layout).toBeDefined();
    });
  });
});
