"""Tests for the CarbonCalc library."""

import unittest
from carboncalc import (
    CarbonCalculator,
    EmissionFactorDB,
    ReportGenerator,
    EmissionRecord,
    BusinessProfile,
)
from carboncalc.models import EmissionCategory, EmissionScope


class TestEmissionFactorDB(unittest.TestCase):
    """Test emission factor database."""

    def setUp(self):
        self.db = EmissionFactorDB()

    def test_get_electricity_factor(self):
        factor = self.db.get_factor(EmissionCategory.ELECTRICITY, "kwh")
        self.assertEqual(factor, 0.417)

    def test_get_transportation_factor(self):
        factor = self.db.get_factor(EmissionCategory.TRANSPORTATION, "km_car")
        self.assertEqual(factor, 0.21)

    def test_invalid_category_unit(self):
        with self.assertRaises(ValueError):
            self.db.get_factor(EmissionCategory.ELECTRICITY, "invalid_unit")

    def test_get_scope(self):
        scope = self.db.get_scope(EmissionCategory.ELECTRICITY)
        self.assertEqual(scope, EmissionScope.SCOPE_2)

    def test_calculate_co2(self):
        co2 = self.db.calculate_co2(EmissionCategory.ELECTRICITY, 1000, "kwh")
        self.assertEqual(co2, 417.0)

    def test_get_available_units(self):
        units = self.db.get_available_units(EmissionCategory.WASTE)
        self.assertIn("kg_landfill", units)
        self.assertIn("kg_recycled", units)

    def test_get_all_categories(self):
        cats = self.db.get_all_categories()
        self.assertEqual(len(cats), 7)


class TestCarbonCalculator(unittest.TestCase):
    """Test carbon calculator engine."""

    def setUp(self):
        self.calc = CarbonCalculator()
        self.records = [
            EmissionRecord(
                category=EmissionCategory.ELECTRICITY,
                quantity=1000, unit="kwh",
                date="2026-01-15", description="Office electricity"
            ),
            EmissionRecord(
                category=EmissionCategory.TRANSPORTATION,
                quantity=500, unit="km_car",
                date="2026-01-20", description="Delivery runs"
            ),
            EmissionRecord(
                category=EmissionCategory.WASTE,
                quantity=200, unit="kg_landfill",
                date="2026-01-25", description="Office waste"
            ),
        ]

    def test_calculate_single(self):
        record = self.records[0]
        result = self.calc.calculate_single(record)
        self.assertEqual(result.co2_kg, 417.0)
        self.assertEqual(result.scope, EmissionScope.SCOPE_2)

    def test_calculate_batch(self):
        results = self.calc.calculate_batch(self.records)
        self.assertEqual(len(results), 3)
        self.assertGreater(results[0].co2_kg, 0)
        self.assertGreater(results[1].co2_kg, 0)

    def test_total_co2(self):
        self.calc.calculate_batch(self.records)
        total = self.calc.get_total_co2_kg(self.records)
        expected = 417.0 + 105.0 + 117.4
        self.assertAlmostEqual(total, expected, places=2)

    def test_breakdown_by_category(self):
        self.calc.calculate_batch(self.records)
        breakdown = self.calc.get_breakdown_by_category(self.records)
        self.assertIn("electricity", breakdown)
        self.assertIn("transportation", breakdown)

    def test_breakdown_by_scope(self):
        self.calc.calculate_batch(self.records)
        breakdown = self.calc.get_breakdown_by_scope(self.records)
        self.assertIn(EmissionScope.SCOPE_2.value, breakdown)

    def test_recommendations(self):
        self.calc.calculate_batch(self.records)
        recs = self.calc.get_recommendations(self.records)
        self.assertGreater(len(recs), 0)

    def test_compare_periods(self):
        records_a = [self.records[0]]
        records_b = [self.records[0], self.records[1]]
        self.calc.calculate_batch(records_a)
        self.calc.calculate_batch(records_b)
        comparison = self.calc.compare_periods(records_a, records_b)
        self.assertTrue(comparison["change_kg"] > 0)
        self.assertFalse(comparison["improved"])


class TestReportGenerator(unittest.TestCase):
    """Test report generation."""

    def setUp(self):
        self.generator = ReportGenerator()
        self.calc = CarbonCalculator()
        self.business = BusinessProfile(
            name="Green Coffee Shop",
            industry="Food & Beverage",
            employee_count=10,
            location="Dublin, Ireland",
            business_id="test-001",
        )
        self.records = [
            EmissionRecord(
                category=EmissionCategory.ELECTRICITY,
                quantity=2000, unit="kwh",
                date="2026-01-15", description="Monthly electricity"
            ),
            EmissionRecord(
                category=EmissionCategory.WASTE,
                quantity=300, unit="kg_landfill",
                date="2026-02-10", description="Monthly waste"
            ),
        ]
        self.calc.calculate_batch(self.records)

    def test_generate_report(self):
        report = self.generator.generate_report(
            self.business, self.records, "2026-01-01", "2026-12-31"
        )
        self.assertGreater(report.total_co2_kg, 0)
        self.assertEqual(report.business.name, "Green Coffee Shop")
        self.assertGreater(len(report.recommendations), 0)

    def test_report_to_dict(self):
        report = self.generator.generate_report(
            self.business, self.records, "2026-01-01", "2026-12-31"
        )
        d = report.to_dict()
        self.assertIn("total_co2_kg", d)
        self.assertIn("breakdown_by_category", d)

    def test_monthly_trend(self):
        trend = self.generator.generate_monthly_trend(self.records)
        self.assertIn("2026-01", trend)
        self.assertIn("2026-02", trend)

    def test_intensity_metrics(self):
        metrics = self.generator.get_intensity_metrics(1000, self.business)
        self.assertEqual(metrics["per_employee_kg"], 100.0)


class TestEmissionRecord(unittest.TestCase):
    """Test EmissionRecord model."""

    def test_to_dict(self):
        record = EmissionRecord(
            category=EmissionCategory.ELECTRICITY,
            quantity=500, unit="kwh",
            date="2026-03-01", description="Test"
        )
        d = record.to_dict()
        self.assertEqual(d["category"], "electricity")
        self.assertEqual(d["quantity"], 500)

    def test_from_dict(self):
        data = {
            "category": "electricity",
            "quantity": 500,
            "unit": "kwh",
            "date": "2026-03-01",
            "description": "Test",
        }
        record = EmissionRecord.from_dict(data)
        self.assertEqual(record.category, EmissionCategory.ELECTRICITY)
        self.assertEqual(record.quantity, 500)


if __name__ == "__main__":
    unittest.main()
