"""ROI-based debt prioritization.

Ranks technical debt items by their return on investment:
which items, if fixed, would save the most engineering time
relative to the effort required to fix them.
"""

from __future__ import annotations

from dataclasses import dataclass
from typing import Any

from ..business.cost_estimator import CostEstimator, CostEstimate


@dataclass
class PrioritizedItem:
    """A debt item ranked by ROI."""

    file_path: str
    issue_type: str
    severity: str
    fix_effort_hours: float
    monthly_savings_usd: float
    annual_savings_usd: float
    roi_months: float
    priority_rank: int
    description: str

    def to_dict(self) -> dict[str, Any]:
        return {
            "file_path": self.file_path,
            "issue_type": self.issue_type,
            "severity": self.severity,
            "fix_effort_hours": round(self.fix_effort_hours, 1),
            "monthly_savings_usd": round(self.monthly_savings_usd, 2),
            "annual_savings_usd": round(self.annual_savings_usd, 2),
            "roi_months": round(self.roi_months, 1),
            "priority_rank": self.priority_rank,
            "description": self.description,
        }


class Prioritizer:
    """Prioritize technical debt by ROI."""

    def __init__(
        self,
        hourly_rate_usd: float = 75.0,
        team_size: int = 5,
    ) -> None:
        self.cost_estimator = CostEstimator(
            hourly_rate_usd=hourly_rate_usd,
            team_size=team_size,
        )

    def prioritize(
        self, scan_result: dict[str, Any], limit: int = 20
    ) -> list[PrioritizedItem]:
        """Generate ROI-prioritized list from scan results.

        Args:
            scan_result: Output from Scanner.scan().
            limit: Maximum items to return.

        Returns:
            List of PrioritizedItem sorted by ROI (fastest payback first).
        """
        items: list[PrioritizedItem] = []
        details = scan_result.get("details", {})

        # Complexity hotspots
        for hotspot in details.get("complexity_hotspots", []):
            estimate = self.cost_estimator.estimate_file(
                file_path=hotspot["file_path"],
                complexity_score=hotspot["complexity"],
                line_count=hotspot.get("line_count", 50),
            )
            items.append(
                PrioritizedItem(
                    file_path=hotspot["file_path"],
                    issue_type="high_complexity",
                    severity=self._severity_from_complexity(hotspot["complexity"]),
                    fix_effort_hours=estimate.fix_effort_hours,
                    monthly_savings_usd=estimate.monthly_cost_usd,
                    annual_savings_usd=estimate.annual_cost_usd,
                    roi_months=estimate.roi_months,
                    priority_rank=0,
                    description=(
                        f"Function '{hotspot['name']}' has complexity {hotspot['complexity']} "
                        f"(rating: {hotspot['rating']})"
                    ),
                )
            )

        # Duplicate blocks
        for dup in details.get("duplicate_blocks", []):
            dup_count = dup.get("duplication_count", 2)
            line_count = dup.get("line_count", 6)
            fix_hours = dup_count * 0.5  # ~30 min per de-duplication
            monthly_savings = dup_count * 0.25 * self.cost_estimator.hourly_rate * 2
            annual_savings = monthly_savings * 12
            roi = (fix_hours * self.cost_estimator.hourly_rate) / monthly_savings if monthly_savings > 0 else 999

            locations_str = ", ".join(
                loc.get("file_path", "?").split("/")[-1]
                for loc in dup.get("locations", [])[:3]
            )
            items.append(
                PrioritizedItem(
                    file_path=dup.get("locations", [{}])[0].get("file_path", "unknown"),
                    issue_type="code_duplication",
                    severity="medium",
                    fix_effort_hours=fix_hours,
                    monthly_savings_usd=monthly_savings,
                    annual_savings_usd=annual_savings,
                    roi_months=min(roi, 999),
                    priority_rank=0,
                    description=(
                        f"{dup_count}x duplicated block ({line_count} lines) "
                        f"in: {locations_str}"
                    ),
                )
            )

        # Dead code
        for dead in details.get("dead_code_items", []):
            if dead.get("confidence", 0) >= 0.8:
                fix_hours = 0.25  # Quick removal
                monthly_savings = 0.1 * self.cost_estimator.hourly_rate  # Small ongoing cost
                annual_savings = monthly_savings * 12
                roi = (fix_hours * self.cost_estimator.hourly_rate) / monthly_savings if monthly_savings > 0 else 999

                items.append(
                    PrioritizedItem(
                        file_path=dead["file_path"],
                        issue_type="dead_code",
                        severity="low",
                        fix_effort_hours=fix_hours,
                        monthly_savings_usd=monthly_savings,
                        annual_savings_usd=annual_savings,
                        roi_months=min(roi, 999),
                        priority_rank=0,
                        description=f"{dead['kind']}: {dead['name']}",
                    )
                )

        # Outdated dependencies
        for dep in details.get("outdated_deps", []):
            if dep.get("severity") in ("critical", "high"):
                fix_hours = 2.0 if dep["severity"] == "critical" else 1.0
                monthly_savings = 4.0 * self.cost_estimator.hourly_rate if dep["severity"] == "critical" else 1.0 * self.cost_estimator.hourly_rate
                annual_savings = monthly_savings * 12
                roi = (fix_hours * self.cost_estimator.hourly_rate) / monthly_savings if monthly_savings > 0 else 999

                items.append(
                    PrioritizedItem(
                        file_path=dep.get("source_file", ""),
                        issue_type="outdated_dependency",
                        severity=dep["severity"],
                        fix_effort_hours=fix_hours,
                        monthly_savings_usd=monthly_savings,
                        annual_savings_usd=annual_savings,
                        roi_months=min(roi, 999),
                        priority_rank=0,
                        description=(
                            f"{dep['name']}: {dep['installed_version']} -> {dep['latest_version']} "
                            f"({dep['major_behind']} major versions behind)"
                        ),
                    )
                )

        # Sort by ROI (fastest payback first), then by annual savings
        items.sort(key=lambda x: (x.roi_months, -x.annual_savings_usd))

        # Assign ranks
        for i, item in enumerate(items):
            item.priority_rank = i + 1

        return items[:limit]

    def _severity_from_complexity(self, complexity: int) -> str:
        if complexity >= 50:
            return "critical"
        elif complexity >= 20:
            return "high"
        elif complexity >= 10:
            return "medium"
        return "low"

    def summary(self, items: list[PrioritizedItem]) -> dict[str, Any]:
        """Generate prioritization summary."""
        if not items:
            return {
                "total_items": 0,
                "total_annual_savings_usd": 0,
                "total_fix_effort_hours": 0,
                "avg_roi_months": 0,
                "quick_wins": 0,
            }

        quick_wins = sum(1 for i in items if i.roi_months <= 2.0)
        valid_rois = [i.roi_months for i in items if i.roi_months < 999]

        return {
            "total_items": len(items),
            "total_annual_savings_usd": round(sum(i.annual_savings_usd for i in items), 2),
            "total_fix_effort_hours": round(sum(i.fix_effort_hours for i in items), 1),
            "avg_roi_months": round(sum(valid_rois) / len(valid_rois), 1) if valid_rois else 0,
            "quick_wins": quick_wins,
            "by_type": self._count_by_type(items),
        }

    def _count_by_type(self, items: list[PrioritizedItem]) -> dict[str, int]:
        counts: dict[str, int] = {}
        for item in items:
            counts[item.issue_type] = counts.get(item.issue_type, 0) + 1
        return counts
