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

import type { TermStatus } from '@/hooks/useContentScore';

import ContentScoreSidebar from './ContentScoreSidebar';

const mockTerms: TermStatus[] = [
  {
    term: 'seo optimization',
    importance_rank: 1,
    tf_idf_score: 0.8,
    present: true,
    frequency: 3,
    competitor_avg_frequency: 0.002,
    in_title: true,
    in_headings: true,
    status: 'covered',
  },
  {
    term: 'search engine',
    importance_rank: 2,
    tf_idf_score: 0.6,
    present: true,
    frequency: 1,
    competitor_avg_frequency: 0.003,
    in_title: false,
    in_headings: false,
    status: 'underused',
  },
  {
    term: 'keyword research',
    importance_rank: 3,
    tf_idf_score: 0.5,
    present: false,
    frequency: 0,
    competitor_avg_frequency: 0.001,
    in_title: false,
    in_headings: false,
    status: 'missing',
  },
];

const defaultProps = {
  overallScore: null as number | null,
  termCoverage: null as {
    score: number;
    covered: number;
    total: number;
    percentage: number;
  } | null,
  wordCountScore: null as {
    score: number;
    draft_count: number;
    competitor_avg: number;
    competitor_median: number;
  } | null,
  structureScore: null as { score: number } | null,
  readabilityScore: null as { score: number } | null,
  wordCountRange: null as { min: number; max: number } | null,
  terms: [] as TermStatus[],
  isLoading: false,
  isAnalyzing: false,
  hasSerpKey: true,
  analysisStatus: 'idle' as const,
  analysisError: null as string | null,
  scoreError: null as string | null,
  onAnalyze: vi.fn(),
  onCancel: vi.fn(),
};

describe('ContentScoreSidebar', () => {
  describe('no SERP key', () => {
    it('shows configure message when SERP key is missing', () => {
      render(<ContentScoreSidebar {...defaultProps} hasSerpKey={false} />);
      expect(screen.getByText('Content Score')).toBeInTheDocument();
      expect(
        screen.getByText(/add your dataforseo credentials to unlock content scoring/i),
      ).toBeInTheDocument();
      expect(screen.getByRole('link', { name: /configure serp api/i })).toHaveAttribute(
        'href',
        '/settings/serp',
      );
    });
  });

  describe('idle state', () => {
    it('shows keyword input when idle', () => {
      render(<ContentScoreSidebar {...defaultProps} />);
      expect(screen.getByPlaceholderText('e.g. best project management tools')).toBeInTheDocument();
    });

    it('calls onAnalyze with keyword on button click', () => {
      const onAnalyze = vi.fn();
      render(<ContentScoreSidebar {...defaultProps} onAnalyze={onAnalyze} />);

      const input = screen.getByPlaceholderText('e.g. best project management tools');
      fireEvent.change(input, { target: { value: 'best seo tools' } });

      const button = screen.getByRole('button');
      fireEvent.click(button);

      expect(onAnalyze).toHaveBeenCalledWith('best seo tools');
    });

    it('calls onAnalyze on Enter key', () => {
      const onAnalyze = vi.fn();
      render(<ContentScoreSidebar {...defaultProps} onAnalyze={onAnalyze} />);

      const input = screen.getByPlaceholderText('e.g. best project management tools');
      fireEvent.change(input, { target: { value: 'best seo tools' } });
      fireEvent.keyDown(input, { key: 'Enter' });

      expect(onAnalyze).toHaveBeenCalledWith('best seo tools');
    });

    it('does not analyze with keyword shorter than 2 chars', () => {
      const onAnalyze = vi.fn();
      render(<ContentScoreSidebar {...defaultProps} onAnalyze={onAnalyze} />);

      const input = screen.getByPlaceholderText('e.g. best project management tools');
      fireEvent.change(input, { target: { value: 'a' } });
      fireEvent.keyDown(input, { key: 'Enter' });

      expect(onAnalyze).not.toHaveBeenCalled();
    });
  });

  describe('analyzing state', () => {
    it('shows pending message', () => {
      render(<ContentScoreSidebar {...defaultProps} isAnalyzing={true} analysisStatus="pending" />);
      expect(screen.getByText('Starting analysis...')).toBeInTheDocument();
    });

    it('shows processing message', () => {
      render(
        <ContentScoreSidebar {...defaultProps} isAnalyzing={true} analysisStatus="processing" />,
      );
      expect(screen.getByText('Analyzing competitors...')).toBeInTheDocument();
    });

    it('shows time estimate', () => {
      render(
        <ContentScoreSidebar {...defaultProps} isAnalyzing={true} analysisStatus="processing" />,
      );
      expect(
        screen.getByText('Fetching top 10 SERP results and extracting NLP terms...'),
      ).toBeInTheDocument();
    });

    it('shows cancel button when onCancel is provided', () => {
      const onCancel = vi.fn();
      render(
        <ContentScoreSidebar
          {...defaultProps}
          isAnalyzing={true}
          analysisStatus="processing"
          onCancel={onCancel}
        />,
      );
      const cancelBtn = screen.getByText('Cancel');
      expect(cancelBtn).toBeInTheDocument();
      fireEvent.click(cancelBtn);
      expect(onCancel).toHaveBeenCalledOnce();
    });

    it('does not show cancel button when onCancel is not provided', () => {
      render(
        <ContentScoreSidebar
          {...defaultProps}
          isAnalyzing={true}
          analysisStatus="processing"
          onCancel={undefined}
        />,
      );
      expect(screen.queryByText('Cancel')).not.toBeInTheDocument();
    });
  });

  describe('failed state', () => {
    it('shows error message', () => {
      render(
        <ContentScoreSidebar
          {...defaultProps}
          analysisStatus="failed"
          analysisError="API credentials invalid"
        />,
      );
      expect(screen.getByText('API credentials invalid')).toBeInTheDocument();
    });

    it('shows default error when no specific error', () => {
      render(
        <ContentScoreSidebar {...defaultProps} analysisStatus="failed" analysisError={null} />,
      );
      expect(screen.getByText('Analysis failed. Try again.')).toBeInTheDocument();
    });

    it('shows retry input', () => {
      render(<ContentScoreSidebar {...defaultProps} analysisStatus="failed" />);
      expect(screen.getByPlaceholderText('e.g. best project management tools')).toBeInTheDocument();
      expect(screen.getByText('Retry')).toBeInTheDocument();
    });
  });

  describe('completed state', () => {
    const completedProps = {
      ...defaultProps,
      analysisStatus: 'completed' as const,
      overallScore: 72,
      termCoverage: { score: 80, covered: 8, total: 10, percentage: 80 },
      wordCountScore: {
        score: 65,
        draft_count: 1200,
        competitor_avg: 1500,
        competitor_median: 1400,
      },
      structureScore: { score: 70 },
      readabilityScore: { score: 75 },
      terms: mockTerms,
    };

    it('shows overall score gauge', () => {
      render(<ContentScoreSidebar {...completedProps} />);
      expect(screen.getByText('72')).toBeInTheDocument();
    });

    it('shows content score header', () => {
      render(<ContentScoreSidebar {...completedProps} />);
      expect(screen.getByText('Content Score')).toBeInTheDocument();
      expect(screen.getByText('vs SERP competitors')).toBeInTheDocument();
    });

    it('shows term coverage metric', () => {
      render(<ContentScoreSidebar {...completedProps} />);
      expect(screen.getByText('Term Coverage')).toBeInTheDocument();
      // QualityMetricCard format="percent" renders "80.0%"
      expect(screen.getByText('80.0%')).toBeInTheDocument();
      expect(screen.getByText('8/10 terms')).toBeInTheDocument();
    });

    it('shows word count metric', () => {
      render(<ContentScoreSidebar {...completedProps} />);
      expect(screen.getByText('Word Count')).toBeInTheDocument();
      // QualityMetricCard format="number" renders with locale formatting
      expect(screen.getByText('1,200')).toBeInTheDocument();
      expect(screen.getByText('Target: ~1400')).toBeInTheDocument();
    });

    it('shows structure and readability metrics', () => {
      render(<ContentScoreSidebar {...completedProps} />);
      expect(screen.getByText('Structure')).toBeInTheDocument();
      expect(screen.getByText('Readability')).toBeInTheDocument();
    });

    it('shows term status summary', () => {
      render(<ContentScoreSidebar {...completedProps} />);
      expect(screen.getByText('1 covered')).toBeInTheDocument();
      expect(screen.getByText('1 underused')).toBeInTheDocument();
      expect(screen.getByText('1 missing')).toBeInTheDocument();
    });

    it('shows term checklist', () => {
      render(<ContentScoreSidebar {...completedProps} />);
      expect(screen.getByText('Terms to Include')).toBeInTheDocument();
      expect(screen.getByText('seo optimization')).toBeInTheDocument();
      expect(screen.getByText('search engine')).toBeInTheDocument();
      expect(screen.getByText('keyword research')).toBeInTheDocument();
    });

    it('shows re-analyze input', () => {
      render(<ContentScoreSidebar {...completedProps} />);
      expect(screen.getByPlaceholderText('e.g. best project management tools')).toBeInTheDocument();
    });

    it('shows score error when present', () => {
      render(<ContentScoreSidebar {...completedProps} scoreError="Failed to score" />);
      expect(screen.getByText('Failed to score')).toBeInTheDocument();
    });

    it('shows loading indicator when score is null', () => {
      render(<ContentScoreSidebar {...completedProps} overallScore={null} isLoading={true} />);
      // Should show loading spinner area instead of gauge
      expect(screen.queryByText('72')).not.toBeInTheDocument();
    });

    it('shows N/A when no scores available', () => {
      render(
        <ContentScoreSidebar
          {...completedProps}
          overallScore={null}
          termCoverage={null}
          wordCountScore={null}
          structureScore={null}
          readabilityScore={null}
          isLoading={false}
        />,
      );
      // QualityMetricCard renders "N/A" for null values
      const naElements = screen.getAllByText('N/A');
      expect(naElements.length).toBeGreaterThanOrEqual(4);
    });
  });
});
