"""Tests for keyword research module."""

from datetime import datetime

import pytest

from src.keyword_research.analyzer import KeywordAnalyzer, KeywordScore
from src.keyword_research.batch_processor import BatchProcessor, BatchResult
from src.keyword_research.google_planner import GoogleKeywordPlanner, KeywordData


def test_keyword_data_creation():
    """Test KeywordData dataclass."""
    data = KeywordData(
        keyword="seo tools",
        avg_monthly_searches=5000,
        competition="MEDIUM",
        low_cpc=1.0,
        high_cpc=3.0,
        trend=[1000] * 12,
        fetched_at=datetime.now(),
    )
    assert data.keyword == "seo tools"
    assert data.avg_monthly_searches == 5000
    assert data.competition == "MEDIUM"


def test_keyword_data_to_dict():
    """Test KeywordData serialization."""
    data = KeywordData(
        keyword="test",
        avg_monthly_searches=1000,
        competition="LOW",
        low_cpc=0.5,
        high_cpc=1.5,
        trend=[800] * 12,
        fetched_at=datetime(2024, 1, 1, 12, 0, 0),
    )
    d = data.to_dict()
    assert d["keyword"] == "test"
    assert d["avg_monthly_searches"] == 1000
    assert "fetched_at" in d


@pytest.mark.asyncio
async def test_google_planner_initialization():
    """Test GoogleKeywordPlanner initialization."""
    planner = GoogleKeywordPlanner("test_key")
    assert planner.api_key == "test_key"
    assert planner.cache_ttl.total_seconds() == 86400  # 24 hours


@pytest.mark.asyncio
async def test_google_planner_context_manager():
    """Test GoogleKeywordPlanner async context manager."""
    async with GoogleKeywordPlanner("test_key") as planner:
        assert planner.session is not None


@pytest.mark.asyncio
async def test_google_planner_cache():
    """Test GoogleKeywordPlanner caching."""
    import tempfile

    with tempfile.TemporaryDirectory() as tmpdir:
        async with GoogleKeywordPlanner("test_key", cache_dir=tmpdir) as planner:
            # First call - fetch from API
            data1 = await planner.get_keyword_data("test_cache")
            assert isinstance(data1, KeywordData)

            # Second call - should use cache
            data2 = await planner.get_keyword_data("test_cache")
            assert data1.keyword == data2.keyword


def test_keyword_analyzer_volume_score():
    """Test volume score calculation."""
    analyzer = KeywordAnalyzer()

    assert analyzer.calculate_volume_score(20000) == 100  # very_high
    assert analyzer.calculate_volume_score(5000) == 80  # high
    assert analyzer.calculate_volume_score(500) == 60  # medium
    assert analyzer.calculate_volume_score(50) == 40  # low
    assert analyzer.calculate_volume_score(5) == 20  # very_low


def test_keyword_analyzer_competition_score():
    """Test competition score calculation."""
    analyzer = KeywordAnalyzer()

    # LOW competition with low CPC
    score = analyzer.calculate_competition_score("LOW", 0.5)
    assert score == 90  # 80 + 10

    # MEDIUM competition with medium CPC
    score = analyzer.calculate_competition_score("MEDIUM", 2.0)
    assert score == 50  # 50 + 0

    # HIGH competition with high CPC
    score = analyzer.calculate_competition_score("HIGH", 5.0)
    assert score == 10  # 20 - 10


def test_keyword_analyzer_analyze():
    """Test full keyword analysis."""
    analyzer = KeywordAnalyzer()
    data = KeywordData(
        keyword="digital marketing",
        avg_monthly_searches=5000,
        competition="MEDIUM",
        low_cpc=1.0,
        high_cpc=3.0,
        trend=[1000] * 12,
        fetched_at=datetime.now(),
    )

    score = analyzer.analyze(data)
    assert isinstance(score, KeywordScore)
    assert 0 <= score.overall_score <= 100
    assert score.recommendation in ["high", "medium", "low"]


def test_keyword_analyzer_recommendation_levels():
    """Test recommendation levels."""
    analyzer = KeywordAnalyzer()

    # High score
    high_data = KeywordData(
        keyword="high",
        avg_monthly_searches=20000,
        competition="LOW",
        low_cpc=0.5,
        high_cpc=1.0,
        trend=[1000] * 12,
        fetched_at=datetime.now(),
    )
    high_score = analyzer.analyze(high_data)
    assert high_score.recommendation == "high"

    # Low score
    low_data = KeywordData(
        keyword="low",
        avg_monthly_searches=50,
        competition="HIGH",
        low_cpc=5.0,
        high_cpc=10.0,
        trend=[100] * 12,
        fetched_at=datetime.now(),
    )
    low_score = analyzer.analyze(low_data)
    assert low_score.recommendation == "low"


@pytest.mark.asyncio
async def test_batch_processor_initialization():
    """Test BatchProcessor initialization."""
    async with GoogleKeywordPlanner("test") as planner:
        processor = BatchProcessor(planner)
        assert processor.planner is planner
        assert processor.max_concurrent == 5
        assert processor.max_retries == 3


@pytest.mark.asyncio
async def test_batch_processor_process():
    """Test batch processing."""
    async with GoogleKeywordPlanner("test") as planner:
        processor = BatchProcessor(planner, max_concurrent=2)
        results = await processor.process(["kw1", "kw2"])

        assert len(results) == 2
        assert all(isinstance(r, BatchResult) for r in results)
        assert all(r.success for r in results)


@pytest.mark.asyncio
async def test_batch_processor_with_progress():
    """Test batch processing with progress."""
    async with GoogleKeywordPlanner("test") as planner:
        processor = BatchProcessor(planner)
        progress = await processor.process_with_progress(["a", "b", "c"])

        assert "results" in progress
        assert "successful_count" in progress
        assert "failed_count" in progress
        assert "total" in progress
        assert progress["total"] == 3


@pytest.mark.asyncio
async def test_batch_processor_progress_callback():
    """Test progress callback."""
    async with GoogleKeywordPlanner("test") as planner:
        processor = BatchProcessor(planner)
        progress_updates = []

        def callback(completed, total):
            progress_updates.append((completed, total))

        await processor.process(["kw1", "kw2"], progress_callback=callback)
        assert len(progress_updates) == 2
