"""
Unit tests for server/business_engines.py.

Run with: cd server && ../venv/bin/python3 -m unittest tests.test_business_engines -v
"""
import os
import sys
import unittest

sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
import business_engines as be  # noqa: E402


class ProfitabilityAnalysisTests(unittest.TestCase):
    def test_aggregates_across_periods(self):
        out = be.profitability_analysis([
            {"dimension_type": "product", "dimension_name": "A", "revenue": 500000, "direct_cost": 300000, "allocated_overhead": 50000},
            {"dimension_type": "product", "dimension_name": "A", "revenue": 500000, "direct_cost": 300000, "allocated_overhead": 50000},
        ])
        row = out["rows"][0]
        self.assertEqual(row["revenue"], 1000000.0)
        self.assertEqual(row["net_margin"], 300000.0)
        self.assertEqual(row["net_margin_pct"], 30.0)

    def test_loss_maker_detected(self):
        out = be.profitability_analysis([
            {"dimension_type": "product", "dimension_name": "A", "revenue": 500000, "direct_cost": 300000, "allocated_overhead": 50000},
            {"dimension_type": "product", "dimension_name": "B", "revenue": 200000, "direct_cost": 250000, "allocated_overhead": 20000},
        ])
        self.assertEqual(len(out["loss_makers"]), 1)
        self.assertEqual(out["loss_makers"][0]["dimension_name"], "B")
        self.assertEqual(out["worst_performer"]["dimension_name"], "B")
        self.assertEqual(out["best_performer"]["dimension_name"], "A")

    def test_revenue_share_sums_to_100(self):
        out = be.profitability_analysis([
            {"dimension_type": "customer", "dimension_name": "X", "revenue": 300000, "direct_cost": 100000},
            {"dimension_type": "customer", "dimension_name": "Y", "revenue": 700000, "direct_cost": 400000},
        ])
        total_share = sum(r["revenue_share_pct"] for r in out["rows"])
        self.assertAlmostEqual(total_share, 100.0, places=1)

    def test_empty_no_crash(self):
        out = be.profitability_analysis([])
        self.assertEqual(out["rows"], [])
        self.assertIsNone(out["best_performer"])
        self.assertEqual(out["cost_structure"]["total_revenue"], 0.0)


class PricingRecommendationTests(unittest.TestCase):
    def test_cost_plus_price(self):
        out = be.pricing_recommendation({"unit_cost": 800, "target_margin_pct": 25})
        self.assertEqual(out["recommended_price"], 1066.67)
        self.assertEqual(out["markup_pct"], 33.33)

    def test_competitor_and_current_price_gaps(self):
        out = be.pricing_recommendation({"unit_cost": 800, "target_margin_pct": 25, "competitor_price": 1200, "current_price": 1000})
        self.assertEqual(out["gap_vs_competitor"], -133.33)
        self.assertEqual(out["current_margin_pct"], 20.0)
        self.assertEqual(out["price_change_needed"], 66.67)

    def test_margin_at_or_above_100_pct_no_price(self):
        out = be.pricing_recommendation({"unit_cost": 500, "target_margin_pct": 100})
        self.assertIsNone(out["recommended_price"])

    def test_no_competitor_or_current_price_omitted(self):
        out = be.pricing_recommendation({"unit_cost": 500, "target_margin_pct": 20})
        self.assertNotIn("competitor_price", out)
        self.assertNotIn("current_price", out)


class BudgetVarianceTests(unittest.TestCase):
    def test_revenue_favorable_when_actual_exceeds_budget(self):
        out = be.budget_variance([{"id": 1, "line_type": "revenue", "budgeted_amount": 1000000, "actual_amount": 1100000}])
        self.assertTrue(out["rows"][0]["favorable"])

    def test_expense_unfavorable_when_actual_exceeds_budget(self):
        out = be.budget_variance([{"id": 2, "line_type": "expense", "budgeted_amount": 400000, "actual_amount": 450000}])
        self.assertFalse(out["rows"][0]["favorable"])
        self.assertEqual(out["unfavorable_count"], 1)

    def test_missing_actual_leaves_variance_none(self):
        out = be.budget_variance([{"id": 3, "line_type": "expense", "budgeted_amount": 100000, "actual_amount": None}])
        self.assertIsNone(out["rows"][0]["variance"])
        self.assertIsNone(out["rows"][0]["favorable"])

    def test_summary_totals(self):
        out = be.budget_variance([
            {"line_type": "revenue", "budgeted_amount": 1000000, "actual_amount": 1100000},
            {"line_type": "expense", "budgeted_amount": 400000, "actual_amount": 450000},
        ])
        self.assertEqual(out["summary"]["budgeted_profit"], 600000.0)
        self.assertEqual(out["summary"]["actual_profit"], 650000.0)


class KpiDashboardTests(unittest.TestCase):
    def test_trend_and_on_target_higher_is_better(self):
        out = be.kpi_dashboard(
            [{"id": 1, "name": "Gross margin %", "target_value": 30, "higher_is_better": 1}],
            {1: [{"period_label": "2081-Q1", "actual_value": 28}, {"period_label": "2081-Q2", "actual_value": 32}]})
        k = out["kpis"][0]
        self.assertEqual(k["trend"], "up")
        self.assertTrue(k["on_target"])
        self.assertEqual(out["off_target_count"], 0)

    def test_lower_is_better_direction(self):
        out = be.kpi_dashboard(
            [{"id": 2, "name": "DSO", "target_value": 45, "higher_is_better": 0}],
            {2: [{"period_label": "2081-Q1", "actual_value": 60}, {"period_label": "2081-Q2", "actual_value": 50}]})
        k = out["kpis"][0]
        self.assertEqual(k["trend"], "down")
        self.assertFalse(k["on_target"])
        self.assertEqual(out["off_target_count"], 1)

    def test_no_values_no_crash(self):
        out = be.kpi_dashboard([{"id": 3, "name": "New KPI"}], {})
        k = out["kpis"][0]
        self.assertIsNone(k["latest_value"])
        self.assertIsNone(k["trend"])
        self.assertIsNone(k["on_target"])

    def test_single_value_no_trend(self):
        out = be.kpi_dashboard([{"id": 4, "name": "X"}], {4: [{"period_label": "2081-Q1", "actual_value": 10}]})
        self.assertIsNone(out["kpis"][0]["trend"])
        self.assertEqual(out["kpis"][0]["latest_value"], 10.0)


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