"""Tests for the ROI-based prioritizer."""

from __future__ import annotations

import pytest

from debtmap.core.prioritizer import Prioritizer, PrioritizedItem
from debtmap.business.cost_estimator import CostEstimator, CostEstimate


@pytest.fixture
def prioritizer() -> Prioritizer:
    return Prioritizer(hourly_rate_usd=100, team_size=5)


@pytest.fixture
def sample_scan_result() -> dict:
    return {
        "scan_id": "test123",
        "repo_path": "/tmp/test",
        "branch": "main",
        "total_score": 45.0,
        "file_count": 10,
        "total_issues": 25,
        "summary": {},
        "details": {
            "complexity_hotspots": [
                {
                    "name": "process_data",
                    "file_path": "/tmp/test/core/processor.py",
                    "line_number": 42,
                    "complexity": 25,
                    "line_count": 80,
                    "rating": "very_complex",
                },
                {
                    "name": "validate_input",
                    "file_path": "/tmp/test/core/validator.py",
                    "line_number": 10,
                    "complexity": 15,
                    "line_count": 40,
                    "rating": "complex",
                },
            ],
            "duplicate_blocks": [
                {
                    "block_hash": "abc123",
                    "line_count": 8,
                    "duplication_count": 3,
                    "locations": [
                        {"file_path": "/tmp/test/handlers/a.py", "start_line": 10, "end_line": 18},
                        {"file_path": "/tmp/test/handlers/b.py", "start_line": 20, "end_line": 28},
                        {"file_path": "/tmp/test/handlers/c.py", "start_line": 5, "end_line": 13},
                    ],
                },
            ],
            "dead_code_items": [
                {
                    "file_path": "/tmp/test/utils/legacy.py",
                    "name": "old_helper",
                    "line_number": 5,
                    "kind": "unused_function",
                    "confidence": 0.9,
                },
            ],
            "outdated_deps": [
                {
                    "name": "requests",
                    "installed_version": "2.25.0",
                    "latest_version": "2.31.0",
                    "severity": "high",
                    "major_behind": 0,
                    "minor_behind": 6,
                    "source_file": "requirements.txt",
                },
            ],
            "uncovered_items": [],
            "missing_docs": [],
        },
    }


class TestPrioritizer:
    def test_prioritize_returns_sorted_items(
        self, prioritizer: Prioritizer, sample_scan_result: dict
    ) -> None:
        items = prioritizer.prioritize(sample_scan_result)

        assert len(items) > 0
        # Check ROI-sorted (ascending)
        for i in range(len(items) - 1):
            assert items[i].roi_months <= items[i + 1].roi_months or (
                items[i].roi_months == items[i + 1].roi_months
                and items[i].annual_savings_usd >= items[i + 1].annual_savings_usd
            )

    def test_priority_ranks_assigned(
        self, prioritizer: Prioritizer, sample_scan_result: dict
    ) -> None:
        items = prioritizer.prioritize(sample_scan_result)
        ranks = [i.priority_rank for i in items]
        assert ranks == list(range(1, len(items) + 1))

    def test_complexity_hotspots_included(
        self, prioritizer: Prioritizer, sample_scan_result: dict
    ) -> None:
        items = prioritizer.prioritize(sample_scan_result)
        complexity_items = [i for i in items if i.issue_type == "high_complexity"]
        assert len(complexity_items) >= 2

    def test_duplication_items_included(
        self, prioritizer: Prioritizer, sample_scan_result: dict
    ) -> None:
        items = prioritizer.prioritize(sample_scan_result)
        dup_items = [i for i in items if i.issue_type == "code_duplication"]
        assert len(dup_items) >= 1

    def test_dead_code_items_included(
        self, prioritizer: Prioritizer, sample_scan_result: dict
    ) -> None:
        items = prioritizer.prioritize(sample_scan_result)
        dead_items = [i for i in items if i.issue_type == "dead_code"]
        assert len(dead_items) >= 1

    def test_outdated_deps_included(
        self, prioritizer: Prioritizer, sample_scan_result: dict
    ) -> None:
        items = prioritizer.prioritize(sample_scan_result)
        dep_items = [i for i in items if i.issue_type == "outdated_dependency"]
        assert len(dep_items) >= 1

    def test_limit_respected(
        self, prioritizer: Prioritizer, sample_scan_result: dict
    ) -> None:
        items = prioritizer.prioritize(sample_scan_result, limit=2)
        assert len(items) <= 2

    def test_to_dict(
        self, prioritizer: Prioritizer, sample_scan_result: dict
    ) -> None:
        items = prioritizer.prioritize(sample_scan_result)
        d = items[0].to_dict()
        assert "file_path" in d
        assert "issue_type" in d
        assert "roi_months" in d
        assert "annual_savings_usd" in d
        assert "priority_rank" in d

    def test_summary(
        self, prioritizer: Prioritizer, sample_scan_result: dict
    ) -> None:
        items = prioritizer.prioritize(sample_scan_result)
        summary = prioritizer.summary(items)

        assert summary["total_items"] == len(items)
        assert summary["total_annual_savings_usd"] > 0
        assert summary["total_fix_effort_hours"] > 0
        assert "quick_wins" in summary
        assert "by_type" in summary

    def test_empty_scan_result(self, prioritizer: Prioritizer) -> None:
        empty = {
            "scan_id": "empty",
            "repo_path": "/tmp/empty",
            "summary": {},
            "details": {},
        }
        items = prioritizer.prioritize(empty)
        assert items == []

    def test_severity_classification(self, prioritizer: Prioritizer) -> None:
        assert prioritizer._severity_from_complexity(60) == "critical"
        assert prioritizer._severity_from_complexity(25) == "high"
        assert prioritizer._severity_from_complexity(12) == "medium"
        assert prioritizer._severity_from_complexity(5) == "low"


class TestCostEstimator:
    def test_basic_estimate(self) -> None:
        estimator = CostEstimator(hourly_rate_usd=100, team_size=5)
        estimate = estimator.estimate_file(
            file_path="test.py",
            complexity_score=20,
            duplication_count=3,
            test_coverage_gap=50,
            coupling_score=8,
            incident_count=2,
        )

        assert estimate.monthly_hours_wasted > 0
        assert estimate.monthly_cost_usd > 0
        assert estimate.annual_cost_usd == estimate.monthly_cost_usd * 12
        assert estimate.fix_effort_hours > 0
        assert estimate.roi_months > 0

    def test_low_debt_costs_less(self) -> None:
        estimator = CostEstimator()
        low = estimator.estimate_file("low.py", complexity_score=2)
        high = estimator.estimate_file("high.py", complexity_score=30)

        assert high.monthly_cost_usd > low.monthly_cost_usd

    def test_incidents_increase_cost(self) -> None:
        estimator = CostEstimator()
        no_incidents = estimator.estimate_file("a.py", incident_count=0)
        many_incidents = estimator.estimate_file("b.py", incident_count=5)

        assert many_incidents.monthly_cost_usd > no_incidents.monthly_cost_usd

    def test_project_aggregation(self) -> None:
        estimator = CostEstimator(hourly_rate_usd=100, team_size=5)
        estimates = [
            estimator.estimate_file("a.py", complexity_score=15),
            estimator.estimate_file("b.py", complexity_score=25),
        ]
        project = estimator.estimate_project(estimates)

        assert project["total_monthly_cost_usd"] > 0
        assert project["total_annual_cost_usd"] > 0
        assert project["total_fix_cost_usd"] > 0
        assert len(project["worst_files"]) <= 10

    def test_empty_project(self) -> None:
        estimator = CostEstimator()
        project = estimator.estimate_project([])
        assert project["total_monthly_cost_usd"] == 0

    def test_to_dict(self) -> None:
        estimator = CostEstimator()
        estimate = estimator.estimate_file("test.py", complexity_score=10)
        d = estimate.to_dict()
        assert "monthly_cost_usd" in d
        assert "annual_cost_usd" in d
        assert "breakdown" in d
