"""
Core carbon footprint calculator engine.
Processes emission records and computes aggregate footprints.
"""

from typing import List, Dict
from .models import EmissionRecord, EmissionCategory, EmissionScope, BusinessProfile
from .emission_factors import EmissionFactorDB


class CarbonCalculator:
    """
    Main calculator class for computing carbon footprints.
    Supports individual and batch calculations with breakdown analysis.
    """

    def __init__(self):
        """Initialize calculator with emission factor database."""
        self._factor_db = EmissionFactorDB()

    def calculate_single(self, record: EmissionRecord) -> EmissionRecord:
        """
        Calculate CO2 for a single emission record.
        Updates the record's co2_kg and scope fields in place and returns it.
        """
        co2 = self._factor_db.calculate_co2(record.category, record.quantity, record.unit)
        scope = self._factor_db.get_scope(record.category)
        record.co2_kg = co2
        record.scope = scope
        return record

    def calculate_batch(self, records: List[EmissionRecord]) -> List[EmissionRecord]:
        """Calculate CO2 for a batch of emission records."""
        return [self.calculate_single(r) for r in records]

    def get_total_co2_kg(self, records: List[EmissionRecord]) -> float:
        """Get total CO2 emissions in kg from a list of records."""
        return round(sum(r.co2_kg for r in records), 4)

    def get_total_co2_tonnes(self, records: List[EmissionRecord]) -> float:
        """Get total CO2 emissions in metric tonnes."""
        return round(self.get_total_co2_kg(records) / 1000, 4)

    def get_breakdown_by_category(self, records: List[EmissionRecord]) -> Dict[str, float]:
        """Get CO2 breakdown by emission category in kg."""
        breakdown = {}
        for record in records:
            cat = record.category.value
            breakdown[cat] = breakdown.get(cat, 0) + record.co2_kg
        return {k: round(v, 4) for k, v in breakdown.items()}

    def get_breakdown_by_scope(self, records: List[EmissionRecord]) -> Dict[str, float]:
        """Get CO2 breakdown by GHG Protocol scope in kg."""
        breakdown = {}
        for record in records:
            scope = record.scope.value
            breakdown[scope] = breakdown.get(scope, 0) + record.co2_kg
        return {k: round(v, 4) for k, v in breakdown.items()}

    def get_recommendations(self, records: List[EmissionRecord]) -> List[str]:
        """
        Generate reduction recommendations based on emission patterns.
        Analyzes the highest emission categories and provides actionable advice.
        """
        if not records:
            return ["Start tracking your emissions to receive personalized recommendations."]

        breakdown = self.get_breakdown_by_category(records)
        total = sum(breakdown.values())
        if total == 0:
            return ["No emissions recorded yet."]

        recommendations = []
        sorted_cats = sorted(breakdown.items(), key=lambda x: x[1], reverse=True)

        for cat_name, co2_kg in sorted_cats:
            percentage = (co2_kg / total) * 100
            if percentage < 5:
                continue

            category = EmissionCategory(cat_name)
            rec = self._get_category_recommendation(category, percentage)
            if rec:
                recommendations.append(rec)

        if not recommendations:
            recommendations.append(
                "Your emissions are well distributed. Continue monitoring and "
                "look for incremental improvements in each category."
            )

        return recommendations

    def _get_category_recommendation(self, category: EmissionCategory, pct: float) -> str:
        """Get a specific recommendation for a high-emission category."""
        recs = {
            EmissionCategory.ELECTRICITY: (
                f"Electricity accounts for {pct:.1f}% of your footprint. "
                "Consider switching to renewable energy providers, installing LED lighting, "
                "and using smart thermostats to reduce consumption."
            ),
            EmissionCategory.NATURAL_GAS: (
                f"Natural gas represents {pct:.1f}% of emissions. "
                "Improve building insulation, upgrade to high-efficiency heating systems, "
                "and consider heat pump alternatives."
            ),
            EmissionCategory.TRANSPORTATION: (
                f"Transportation contributes {pct:.1f}% of your footprint. "
                "Optimize delivery routes, transition to electric vehicles, "
                "and encourage carpooling among employees."
            ),
            EmissionCategory.WASTE: (
                f"Waste disposal accounts for {pct:.1f}% of emissions. "
                "Implement recycling programs, reduce packaging, "
                "and compost organic waste to minimize landfill contributions."
            ),
            EmissionCategory.WATER: (
                f"Water usage contributes {pct:.1f}% of your footprint. "
                "Install low-flow fixtures, fix leaks promptly, "
                "and consider rainwater harvesting systems."
            ),
            EmissionCategory.BUSINESS_TRAVEL: (
                f"Business travel represents {pct:.1f}% of emissions. "
                "Use video conferencing when possible, choose rail over flights "
                "for short distances, and offset remaining travel emissions."
            ),
            EmissionCategory.REFRIGERANTS: (
                f"Refrigerants account for {pct:.1f}% of your footprint. "
                "Schedule regular maintenance checks for leaks, "
                "and transition to low-GWP refrigerant alternatives."
            ),
        }
        return recs.get(category, "")

    def compare_periods(
        self, records_a: List[EmissionRecord], records_b: List[EmissionRecord]
    ) -> dict:
        """
        Compare emissions between two periods.
        Returns comparison metrics showing change.
        """
        total_a = self.get_total_co2_kg(records_a)
        total_b = self.get_total_co2_kg(records_b)
        change_kg = total_b - total_a
        change_pct = ((change_kg / total_a) * 100) if total_a > 0 else 0

        return {
            "period_a_co2_kg": total_a,
            "period_b_co2_kg": total_b,
            "change_kg": round(change_kg, 4),
            "change_percentage": round(change_pct, 2),
            "improved": change_kg < 0,
        }
