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

import BatchHistoryCard from '@/Components/Batch/BatchHistoryCard';

vi.mock('@inertiajs/react', () => ({
  Link: ({ children, href }: { children: React.ReactNode; href: string }) => (
    <a href={href}>{children}</a>
  ),
}));

describe('BatchHistoryCard', () => {
  const baseBatchJob = {
    id: 1,
    created_at: '2026-02-25T10:30:00Z',
    completed_at: null,
    status: 'completed' as const,
    total_jobs: 10,
    completed_jobs: 10,
    failed_jobs: 2,
    total_actual_tokens: 15000,
    total_estimated_tokens: 14000,
    total_actual_cost: 0.45,
    total_estimated_cost: 0.42,
  };

  it('renders batch job with completed status', () => {
    render(<BatchHistoryCard batchJob={baseBatchJob} siteId={1} />);

    expect(screen.getByText('Completed')).toBeInTheDocument();
  });

  it('renders batch job with pending status', () => {
    const pendingBatch = { ...baseBatchJob, status: 'pending' as const };

    render(<BatchHistoryCard batchJob={pendingBatch} siteId={1} />);

    // "Pending" appears in both the status badge and the job counter label
    expect(screen.getAllByText('Pending').length).toBeGreaterThanOrEqual(1);
  });

  it('renders batch job with processing status', () => {
    const processingBatch = {
      ...baseBatchJob,
      status: 'processing' as const,
      completed_jobs: 5,
    };

    render(<BatchHistoryCard batchJob={processingBatch} siteId={1} />);

    expect(screen.getByText('Processing')).toBeInTheDocument();
  });

  it('renders batch job with failed status', () => {
    const failedBatch = { ...baseBatchJob, status: 'failed' as const };

    render(<BatchHistoryCard batchJob={failedBatch} siteId={1} />);

    // "Failed" appears in both the status badge and the job counter label
    expect(screen.getAllByText('Failed').length).toBeGreaterThanOrEqual(1);
  });

  it('displays total jobs count', () => {
    render(<BatchHistoryCard batchJob={baseBatchJob} siteId={1} />);

    expect(screen.getByText('Total Jobs')).toBeInTheDocument();
    expect(screen.getByText('10')).toBeInTheDocument();
  });

  it('calculates and displays successful jobs (completed - failed)', () => {
    render(<BatchHistoryCard batchJob={baseBatchJob} siteId={1} />);

    // 10 completed - 2 failed = 8 successful
    expect(screen.getByText('8')).toBeInTheDocument();
  });

  it('displays failed jobs count', () => {
    render(<BatchHistoryCard batchJob={baseBatchJob} siteId={1} />);

    expect(screen.getByText('Failed')).toBeInTheDocument();
    expect(screen.getByText('2')).toBeInTheDocument();
  });

  it('calculates and displays pending jobs (total - completed - failed)', () => {
    const batchWithPending = {
      ...baseBatchJob,
      total_jobs: 15,
      completed_jobs: 10,
      failed_jobs: 2,
    };

    render(<BatchHistoryCard batchJob={batchWithPending} siteId={1} />);

    // 15 total - 10 completed - 2 failed = 3 pending
    expect(screen.getByText('Pending')).toBeInTheDocument();
    expect(screen.getByText('3')).toBeInTheDocument();
  });

  it('uses actual tokens when available', () => {
    render(<BatchHistoryCard batchJob={baseBatchJob} siteId={1} />);

    // 15000 tokens formatted as 15.0K
    expect(screen.getByText('15.0K')).toBeInTheDocument();
  });

  it('falls back to estimated tokens when actual is null', () => {
    const batchWithoutActual = {
      ...baseBatchJob,
      total_actual_tokens: null,
    };

    render(<BatchHistoryCard batchJob={batchWithoutActual} siteId={1} />);

    // 14000 tokens formatted as 14.0K
    expect(screen.getByText('14.0K')).toBeInTheDocument();
  });

  it('uses actual cost when available', () => {
    render(<BatchHistoryCard batchJob={baseBatchJob} siteId={1} />);

    expect(screen.getByText('$0.45')).toBeInTheDocument();
  });

  it('falls back to estimated cost when actual is null', () => {
    const batchWithoutActualCost = {
      ...baseBatchJob,
      total_actual_cost: null,
    };

    render(<BatchHistoryCard batchJob={batchWithoutActualCost} siteId={1} />);

    expect(screen.getByText('$0.42')).toBeInTheDocument();
  });

  it('formats tokens with M suffix for millions', () => {
    const batchWithMillions = {
      ...baseBatchJob,
      total_actual_tokens: 2_500_000,
    };

    render(<BatchHistoryCard batchJob={batchWithMillions} siteId={1} />);

    expect(screen.getByText('2.5M')).toBeInTheDocument();
  });

  it('formats tokens without suffix for small numbers', () => {
    const batchWithSmallTokens = {
      ...baseBatchJob,
      total_actual_tokens: 500,
    };

    render(<BatchHistoryCard batchJob={batchWithSmallTokens} siteId={1} />);

    expect(screen.getByText('500')).toBeInTheDocument();
  });

  it('formats cost as "<$0.01" for very small amounts', () => {
    const batchWithSmallCost = {
      ...baseBatchJob,
      total_actual_cost: 0.005,
    };

    render(<BatchHistoryCard batchJob={batchWithSmallCost} siteId={1} />);

    expect(screen.getByText('<$0.01')).toBeInTheDocument();
  });

  it('displays formatted creation date', () => {
    render(<BatchHistoryCard batchJob={baseBatchJob} siteId={1} />);

    // Date should be formatted (exact format depends on locale)
    expect(screen.getByText(/Feb/)).toBeInTheDocument();
  });

  it('shows progress bar for processing status', () => {
    const processingBatch = {
      ...baseBatchJob,
      status: 'processing' as const,
      total_jobs: 10,
      completed_jobs: 5,
      failed_jobs: 0,
    };

    render(<BatchHistoryCard batchJob={processingBatch} siteId={1} />);

    expect(screen.getByText('Progress')).toBeInTheDocument();
    expect(screen.getByText('50%')).toBeInTheDocument();

    const progressBar = screen.getByRole('progressbar');
    expect(progressBar).toHaveAttribute('aria-valuenow', '50');
  });

  it('does not show progress bar for completed status', () => {
    render(<BatchHistoryCard batchJob={baseBatchJob} siteId={1} />);

    expect(screen.queryByText('Progress')).not.toBeInTheDocument();
    expect(screen.queryByRole('progressbar')).not.toBeInTheDocument();
  });

  it('does not show progress bar for failed status', () => {
    const failedBatch = { ...baseBatchJob, status: 'failed' as const };

    render(<BatchHistoryCard batchJob={failedBatch} siteId={1} />);

    expect(screen.queryByText('Progress')).not.toBeInTheDocument();
    expect(screen.queryByRole('progressbar')).not.toBeInTheDocument();
  });

  it('calculates correct progress percentage', () => {
    const processingBatch = {
      ...baseBatchJob,
      status: 'processing' as const,
      total_jobs: 100,
      completed_jobs: 75,
      failed_jobs: 10,
    };

    render(<BatchHistoryCard batchJob={processingBatch} siteId={1} />);

    // 75/100 = 75%
    expect(screen.getByText('75%')).toBeInTheDocument();
  });

  it('handles zero total jobs gracefully', () => {
    const emptyBatch = {
      ...baseBatchJob,
      total_jobs: 0,
      completed_jobs: 0,
      failed_jobs: 0,
    };

    render(<BatchHistoryCard batchJob={emptyBatch} siteId={1} />);

    // Multiple zeros appear (total, success, failed, pending)
    expect(screen.getAllByText('0').length).toBeGreaterThanOrEqual(1);
  });

  it('renders View Details link with correct route', () => {
    render(<BatchHistoryCard batchJob={baseBatchJob} siteId={5} />);

    const link = screen.getByRole('link', { name: /View Details/i });
    expect(link).toBeInTheDocument();
    expect(link).toHaveAttribute('href', '/sites/5/batch-ai/1');
  });

  it('applies success badge variant for completed status', () => {
    render(<BatchHistoryCard batchJob={baseBatchJob} siteId={1} />);

    // Badge component uses semantic CSS custom property classes (bg-success), not Tailwind color classes
    expect(screen.getByText('Completed')).toBeInTheDocument();
  });

  it('applies destructive badge variant for failed status', () => {
    const failedBatch = { ...baseBatchJob, status: 'failed' as const };
    render(<BatchHistoryCard batchJob={failedBatch} siteId={1} />);

    // Badge component uses semantic CSS custom property classes (bg-destructive), not Tailwind color classes
    expect(screen.getAllByText('Failed').length).toBeGreaterThanOrEqual(1);
  });

  it('displays all job count sections', () => {
    render(<BatchHistoryCard batchJob={baseBatchJob} siteId={1} />);

    expect(screen.getByText('Total Jobs')).toBeInTheDocument();
    expect(screen.getByText('Success')).toBeInTheDocument();
    expect(screen.getByText('Failed')).toBeInTheDocument();
    expect(screen.getByText('Pending')).toBeInTheDocument();
  });

  it('displays tokens and cost sections', () => {
    render(<BatchHistoryCard batchJob={baseBatchJob} siteId={1} />);

    expect(screen.getByText('Tokens')).toBeInTheDocument();
    expect(screen.getByText('Cost')).toBeInTheDocument();
  });

  it('rounds progress percentage correctly', () => {
    const processingBatch = {
      ...baseBatchJob,
      status: 'processing' as const,
      total_jobs: 3,
      completed_jobs: 1,
      failed_jobs: 0,
    };

    render(<BatchHistoryCard batchJob={processingBatch} siteId={1} />);

    // 1/3 = 33.333... should round to 33%
    expect(screen.getByText('33%')).toBeInTheDocument();
  });

  it('handles completed_jobs including failed jobs', () => {
    // In the model, completed_jobs includes both successful and failed jobs
    const batch = {
      ...baseBatchJob,
      total_jobs: 20,
      completed_jobs: 15,
      failed_jobs: 5,
    };

    render(<BatchHistoryCard batchJob={batch} siteId={1} />);

    // Successful = 15 - 5 = 10
    expect(screen.getByText('10')).toBeInTheDocument();
    // Failed = 5
    expect(screen.getByText('5')).toBeInTheDocument();
    // Pending = 20 - 15 - 5 = 0
    // The '0' for pending will appear, let's verify it's in the Pending section
    const pendingSection = screen.getByText('Pending').closest('div');
    expect(pendingSection).toHaveTextContent('0');
  });
});
