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

import KeywordOpportunityCard from './KeywordOpportunityCard';

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

vi.mock('@/Components/Shared/MetricDelta', () => ({
  default: ({ value, format }: { value: number; format?: string }) => (
    <span data-testid="metric-delta">
      {value > 0 ? '+' : '-'}
      {Math.abs(value).toFixed(1)}
      {format === 'percent' ? '%' : ''}
    </span>
  ),
}));

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

describe('KeywordOpportunityCard', () => {
  const baseOpportunity = {
    opportunity_type: 'keyword_opportunity' as const,
    opportunity_id: 1,
    page_url: 'https://example.com/page',
    demand: {
      query: 'test keyword',
      position: 5.2,
      impressions: 1000,
      clicks: 50,
      ctr: 0.05,
    },
    issue: 'Keyword ranking in striking distance',
    action: 'content_optimization',
    confidence: 0.85,
    impact_score: 90.5,
    keyword_opportunity_type: 'striking_distance' as const,
    reasoning: 'This keyword is close to ranking in top 3',
  };

  beforeEach(() => {
    vi.clearAllMocks();
  });

  describe('Basic Rendering', () => {
    it('renders keyword opportunity type badge', () => {
      render(<KeywordOpportunityCard opportunity={baseOpportunity} siteId={1} />);

      const badge = screen.getByTestId('badge');
      expect(badge).toBeInTheDocument();
      expect(badge).toHaveTextContent('Striking Distance');
    });

    it('renders page URL', () => {
      render(<KeywordOpportunityCard opportunity={baseOpportunity} siteId={1} />);

      expect(screen.getByText('https://example.com/page')).toBeInTheDocument();
    });

    it('renders impact score', () => {
      render(<KeywordOpportunityCard opportunity={baseOpportunity} siteId={1} />);

      expect(screen.getByText('Impact')).toBeInTheDocument();
      expect(screen.getByText('90.5')).toBeInTheDocument();
    });

    it('renders confidence score as percentage', () => {
      render(<KeywordOpportunityCard opportunity={baseOpportunity} siteId={1} />);

      expect(screen.getByText('Confidence')).toBeInTheDocument();
      expect(screen.getByText('85%')).toBeInTheDocument();
    });

    it('renders query', () => {
      render(<KeywordOpportunityCard opportunity={baseOpportunity} siteId={1} />);

      expect(screen.getByText('"test keyword"')).toBeInTheDocument();
    });

    it('renders issue description', () => {
      render(<KeywordOpportunityCard opportunity={baseOpportunity} siteId={1} />);

      expect(screen.getByText('Issue')).toBeInTheDocument();
      expect(screen.getByText('Keyword ranking in striking distance')).toBeInTheDocument();
    });

    it('renders recommended action with label', () => {
      render(<KeywordOpportunityCard opportunity={baseOpportunity} siteId={1} />);

      expect(screen.getByText('Recommended Action')).toBeInTheDocument();
      expect(screen.getByText('Optimize Content')).toBeInTheDocument();
    });

    it('renders action as-is when no label mapping exists', () => {
      const opportunity = {
        ...baseOpportunity,
        action: 'unknown_action',
      };

      render(<KeywordOpportunityCard opportunity={opportunity} siteId={1} />);

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

  describe('Selection Checkbox', () => {
    it('does not render checkbox when onToggleSelection is not provided', () => {
      render(<KeywordOpportunityCard opportunity={baseOpportunity} siteId={1} />);

      expect(screen.queryByLabelText(/Select opportunity/)).not.toBeInTheDocument();
    });

    it('renders checkbox when onToggleSelection is provided', () => {
      const onToggle = vi.fn();
      render(
        <KeywordOpportunityCard
          opportunity={baseOpportunity}
          siteId={1}
          onToggleSelection={onToggle}
        />,
      );

      expect(
        screen.getByLabelText('Select opportunity: Keyword ranking in striking distance'),
      ).toBeInTheDocument();
    });

    it('checkbox reflects selected state', () => {
      const onToggle = vi.fn();
      const { rerender } = render(
        <KeywordOpportunityCard
          opportunity={baseOpportunity}
          siteId={1}
          selected={false}
          onToggleSelection={onToggle}
        />,
      );

      const checkbox = screen.getByRole('checkbox') as HTMLInputElement;
      expect(checkbox.checked).toBe(false);

      rerender(
        <KeywordOpportunityCard
          opportunity={baseOpportunity}
          siteId={1}
          selected={true}
          onToggleSelection={onToggle}
        />,
      );

      expect(checkbox.checked).toBe(true);
    });

    it('calls onToggleSelection when checkbox is clicked', async () => {
      const user = userEvent.setup();
      const onToggle = vi.fn();

      render(
        <KeywordOpportunityCard
          opportunity={baseOpportunity}
          siteId={1}
          onToggleSelection={onToggle}
        />,
      );

      const checkbox = screen.getByRole('checkbox');
      await user.click(checkbox);

      expect(onToggle).toHaveBeenCalledTimes(1);
    });
  });

  describe('Demand Metrics - Striking Distance', () => {
    it('renders common metrics for striking distance', () => {
      render(<KeywordOpportunityCard opportunity={baseOpportunity} siteId={1} />);

      expect(screen.getByText('Position')).toBeInTheDocument();
      expect(screen.getByText('5.2')).toBeInTheDocument();

      expect(screen.getByText('Impressions')).toBeInTheDocument();
      expect(screen.getByText('1,000')).toBeInTheDocument();

      expect(screen.getByText('Clicks')).toBeInTheDocument();
      expect(screen.getByText('50')).toBeInTheDocument();

      // CTR appears once as a label
      expect(screen.getByText('CTR')).toBeInTheDocument();
      expect(screen.getByText('5.00%')).toBeInTheDocument();
    });
  });

  describe('Demand Metrics - CTR Gap', () => {
    it('renders CTR gap metrics', () => {
      const opportunity = {
        ...baseOpportunity,
        keyword_opportunity_type: 'ctr_gap' as const,
        demand: {
          ...baseOpportunity.demand,
          expected_ctr: 0.08,
          ctr_gap_percent: 37.5,
        },
      };

      render(<KeywordOpportunityCard opportunity={opportunity} siteId={1} />);

      // CTR Gap appears twice: in badge and in metrics section
      const ctrGapElements = screen.getAllByText('CTR Gap');
      expect(ctrGapElements).toHaveLength(2);
      expect(screen.getByText('Actual CTR')).toBeInTheDocument();
      expect(screen.getByText('Expected CTR')).toBeInTheDocument();
      expect(screen.getByText('8.00%')).toBeInTheDocument();
    });

    it('renders CTR gap delta', () => {
      const opportunity = {
        ...baseOpportunity,
        keyword_opportunity_type: 'ctr_gap' as const,
        demand: {
          ...baseOpportunity.demand,
          expected_ctr: 0.08,
          ctr_gap_percent: 37.5,
        },
      };

      render(<KeywordOpportunityCard opportunity={opportunity} siteId={1} />);

      const metricDelta = screen.getByTestId('metric-delta');
      expect(metricDelta).toBeInTheDocument();
      // MetricDelta receives negative value (-37.5)
      expect(metricDelta).toHaveTextContent('-37.5%');
    });
  });

  describe('Demand Metrics - Rising Query', () => {
    it('renders rising query growth trend', () => {
      const opportunity = {
        ...baseOpportunity,
        keyword_opportunity_type: 'rising_query' as const,
        demand: {
          ...baseOpportunity.demand,
          growth_percent: 125.5,
          weeks_tracked: 8,
        },
      };

      render(<KeywordOpportunityCard opportunity={opportunity} siteId={1} />);

      expect(screen.getByText('Growth Trend')).toBeInTheDocument();
      expect(screen.getByText('Tracked for 8 weeks')).toBeInTheDocument();
    });

    it('renders growth percentage delta', () => {
      const opportunity = {
        ...baseOpportunity,
        keyword_opportunity_type: 'rising_query' as const,
        demand: {
          ...baseOpportunity.demand,
          growth_percent: 125.5,
        },
      };

      render(<KeywordOpportunityCard opportunity={opportunity} siteId={1} />);

      const metricDelta = screen.getByTestId('metric-delta');
      expect(metricDelta).toBeInTheDocument();
      expect(metricDelta).toHaveTextContent('+125.5%');
    });

    it('renders without weeks tracked if not provided', () => {
      const opportunity = {
        ...baseOpportunity,
        keyword_opportunity_type: 'rising_query' as const,
        demand: {
          ...baseOpportunity.demand,
          growth_percent: 125.5,
        },
      };

      render(<KeywordOpportunityCard opportunity={opportunity} siteId={1} />);

      expect(screen.getByText('Growth Trend')).toBeInTheDocument();
      expect(screen.queryByText(/Tracked for/)).not.toBeInTheDocument();
    });
  });

  describe('Demand Metrics - Content Gap', () => {
    it('renders content gap coverage', () => {
      const opportunity = {
        ...baseOpportunity,
        keyword_opportunity_type: 'content_gap' as const,
        demand: {
          ...baseOpportunity.demand,
          coverage_percentage: 45.5,
        },
      };

      render(<KeywordOpportunityCard opportunity={opportunity} siteId={1} />);

      expect(screen.getByText('Content Coverage')).toBeInTheDocument();
      expect(screen.getByText('45.50%')).toBeInTheDocument();
    });
  });

  describe('Expandable Details', () => {
    it('renders Details button', () => {
      render(<KeywordOpportunityCard opportunity={baseOpportunity} siteId={1} />);

      expect(screen.getByRole('button', { name: /Details/i })).toBeInTheDocument();
    });

    it('details are initially collapsed', () => {
      render(<KeywordOpportunityCard opportunity={baseOpportunity} siteId={1} />);

      const detailsButton = screen.getByRole('button', { name: /Details/i });
      expect(detailsButton).toHaveAttribute('aria-expanded', 'false');
      expect(screen.queryByText('Reasoning')).not.toBeInTheDocument();
    });

    it('expands details when button is clicked', async () => {
      const user = userEvent.setup();

      render(<KeywordOpportunityCard opportunity={baseOpportunity} siteId={1} />);

      const detailsButton = screen.getByRole('button', { name: /Details/i });
      await user.click(detailsButton);

      expect(detailsButton).toHaveAttribute('aria-expanded', 'true');
      expect(screen.getByText('Reasoning')).toBeInTheDocument();
      expect(screen.getByText('This keyword is close to ranking in top 3')).toBeInTheDocument();
    });

    it('collapses details when button is clicked again', async () => {
      const user = userEvent.setup();

      render(<KeywordOpportunityCard opportunity={baseOpportunity} siteId={1} />);

      const detailsButton = screen.getByRole('button', { name: /Details/i });

      // Expand
      await user.click(detailsButton);
      expect(screen.getByText('Reasoning')).toBeInTheDocument();

      // Collapse
      await user.click(detailsButton);
      expect(screen.queryByText('Reasoning')).not.toBeInTheDocument();
    });

    it('renders evidence when provided', async () => {
      const user = userEvent.setup();
      const opportunity = {
        ...baseOpportunity,
        evidence: {
          competitors_in_top_3: 5,
          domain_authority: 45,
        },
      };

      render(<KeywordOpportunityCard opportunity={opportunity} siteId={1} />);

      const detailsButton = screen.getByRole('button', { name: /Details/i });
      await user.click(detailsButton);

      expect(screen.getByText('Evidence')).toBeInTheDocument();
      const evidenceContent = screen.getByText(/"competitors_in_top_3": 5/);
      expect(evidenceContent).toBeInTheDocument();
    });

    it('does not render evidence section when empty', async () => {
      const user = userEvent.setup();
      const opportunity = {
        ...baseOpportunity,
        evidence: {},
      };

      render(<KeywordOpportunityCard opportunity={opportunity} siteId={1} />);

      const detailsButton = screen.getByRole('button', { name: /Details/i });
      await user.click(detailsButton);

      expect(screen.queryByText('Evidence')).not.toBeInTheDocument();
    });

    it('renders lifecycle status when provided', async () => {
      const user = userEvent.setup();
      const opportunity = {
        ...baseOpportunity,
        lifecycle_status: 'approved',
      };

      render(<KeywordOpportunityCard opportunity={opportunity} siteId={1} />);

      const detailsButton = screen.getByRole('button', { name: /Details/i });
      await user.click(detailsButton);

      // Status appears twice (once in label, once in value)
      const statusElements = screen.getAllByText('Status');
      expect(statusElements.length).toBeGreaterThan(0);
      expect(screen.getByText('approved')).toBeInTheDocument();
    });

    it('formats lifecycle status with underscores replaced', async () => {
      const user = userEvent.setup();
      const opportunity = {
        ...baseOpportunity,
        lifecycle_status: 'in_review',
      };

      render(<KeywordOpportunityCard opportunity={opportunity} siteId={1} />);

      const detailsButton = screen.getByRole('button', { name: /Details/i });
      await user.click(detailsButton);

      expect(screen.getByText('in review')).toBeInTheDocument();
    });
  });

  describe('Opportunity Type Badges', () => {
    it('renders CTR Gap badge', () => {
      const opportunity = {
        ...baseOpportunity,
        keyword_opportunity_type: 'ctr_gap' as const,
      };

      render(<KeywordOpportunityCard opportunity={opportunity} siteId={1} />);

      expect(screen.getByText('CTR Gap')).toBeInTheDocument();
    });

    it('renders Rising Query badge', () => {
      const opportunity = {
        ...baseOpportunity,
        keyword_opportunity_type: 'rising_query' as const,
      };

      render(<KeywordOpportunityCard opportunity={opportunity} siteId={1} />);

      expect(screen.getByText('Rising Query')).toBeInTheDocument();
    });

    it('renders Content Gap badge', () => {
      const opportunity = {
        ...baseOpportunity,
        keyword_opportunity_type: 'content_gap' as const,
      };

      render(<KeywordOpportunityCard opportunity={opportunity} siteId={1} />);

      expect(screen.getByText('Content Gap')).toBeInTheDocument();
    });

    it('handles unknown opportunity type gracefully', () => {
      const opportunity = {
        ...baseOpportunity,
        keyword_opportunity_type: 'unknown_type' as
          | 'striking_distance'
          | 'ctr_gap'
          | 'rising_query'
          | 'content_gap',
      };

      render(<KeywordOpportunityCard opportunity={opportunity} siteId={1} />);

      // Should replace underscores with spaces
      expect(screen.getByText('unknown type')).toBeInTheDocument();
    });
  });

  describe('Action Labels', () => {
    it('renders meta tag optimization label', () => {
      const opportunity = {
        ...baseOpportunity,
        action: 'meta_tag_optimization',
      };

      render(<KeywordOpportunityCard opportunity={opportunity} siteId={1} />);

      expect(screen.getByText('Optimize Meta Tags')).toBeInTheDocument();
    });

    it('renders content creation label', () => {
      const opportunity = {
        ...baseOpportunity,
        action: 'content_creation',
      };

      render(<KeywordOpportunityCard opportunity={opportunity} siteId={1} />);

      expect(screen.getByText('Create Content')).toBeInTheDocument();
    });

    it('renders keyword optimization label', () => {
      const opportunity = {
        ...baseOpportunity,
        action: 'keyword_optimization',
      };

      render(<KeywordOpportunityCard opportunity={opportunity} siteId={1} />);

      expect(screen.getByText('Optimize Keywords')).toBeInTheDocument();
    });
  });

  describe('View Details Link', () => {
    it('does not render View Details link when detailRoute is #', () => {
      render(<KeywordOpportunityCard opportunity={baseOpportunity} siteId={1} />);

      expect(screen.queryByText('View Details')).not.toBeInTheDocument();
    });
  });

  describe('Number Formatting', () => {
    it('formats large numbers with locale separators', () => {
      const opportunity = {
        ...baseOpportunity,
        demand: {
          ...baseOpportunity.demand,
          impressions: 1234567,
          clicks: 12345,
        },
      };

      render(<KeywordOpportunityCard opportunity={opportunity} siteId={1} />);

      expect(screen.getByText('1,234,567')).toBeInTheDocument();
      expect(screen.getByText('12,345')).toBeInTheDocument();
    });

    it('formats position to one decimal place', () => {
      const opportunity = {
        ...baseOpportunity,
        demand: {
          ...baseOpportunity.demand,
          position: 3.789,
        },
      };

      render(<KeywordOpportunityCard opportunity={opportunity} siteId={1} />);

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

    it('formats percentages to two decimal places', () => {
      const opportunity = {
        ...baseOpportunity,
        demand: {
          ...baseOpportunity.demand,
          ctr: 0.12345,
        },
      };

      render(<KeywordOpportunityCard opportunity={opportunity} siteId={1} />);

      expect(screen.getByText('12.35%')).toBeInTheDocument();
    });
  });
});
