"""Unit tests for the Campaign ROI Calculator."""

import sys
import os

import pytest

sys.path.insert(0, os.path.join(
    os.path.dirname(__file__), "..", "marketing-skill", "skills", "campaign-analytics", "scripts"
))
from campaign_roi_calculator import (
    safe_divide,
    get_benchmark,
    assess_performance,
    calculate_campaign_metrics,
    calculate_portfolio_summary,
)


class TestSafeDivide:
    def test_normal(self):
        assert safe_divide(10, 2) == 5.0

    def test_zero_denominator(self):
        assert safe_divide(10, 0) == 0.0

    def test_custom_default(self):
        assert safe_divide(10, 0, -1.0) == -1.0


class TestGetBenchmark:
    def test_known_channel(self):
        result = get_benchmark("ctr", "email")
        assert result == (1.0, 2.5, 5.0)

    def test_falls_back_to_default(self):
        result = get_benchmark("ctr", "nonexistent_channel")
        assert result == (0.5, 2.0, 5.0)

    def test_unknown_metric(self):
        result = get_benchmark("nonexistent_metric", "email")
        assert result == (0, 0, 0)


class TestAssessPerformance:
    def test_excellent_high_is_better(self):
        assert assess_performance(10.0, (1.0, 3.0, 5.0), higher_is_better=True) == "excellent"

    def test_good_high_is_better(self):
        assert assess_performance(3.5, (1.0, 3.0, 5.0), higher_is_better=True) == "good"

    def test_below_target_high_is_better(self):
        assert assess_performance(1.5, (1.0, 3.0, 5.0), higher_is_better=True) == "below_target"

    def test_underperforming_high_is_better(self):
        assert assess_performance(0.5, (1.0, 3.0, 5.0), higher_is_better=True) == "underperforming"

    def test_excellent_low_is_better(self):
        # For cost metrics, lower is better
        assert assess_performance(0.5, (1.0, 3.0, 5.0), higher_is_better=False) == "excellent"

    def test_underperforming_low_is_better(self):
        assert assess_performance(10.0, (1.0, 3.0, 5.0), higher_is_better=False) == "underperforming"


class TestCalculateCampaignMetrics:
    @pytest.fixture
    def campaign(self):
        return {
            "name": "Test Campaign",
            "channel": "paid_search",
            "spend": 1000.0,
            "revenue": 5000.0,
            "impressions": 100000,
            "clicks": 3000,
            "leads": 100,
            "customers": 10,
        }

    def test_roi(self, campaign):
        result = calculate_campaign_metrics(campaign)
        # ROI = (5000 - 1000) / 1000 * 100 = 400%
        assert result["metrics"]["roi_pct"] == 400.0

    def test_roas(self, campaign):
        result = calculate_campaign_metrics(campaign)
        # ROAS = 5000 / 1000 = 5.0
        assert result["metrics"]["roas"] == 5.0

    def test_cpa(self, campaign):
        result = calculate_campaign_metrics(campaign)
        # CPA = 1000 / 10 = 100.0
        assert result["metrics"]["cpa"] == 100.0

    def test_ctr(self, campaign):
        result = calculate_campaign_metrics(campaign)
        # CTR = 3000 / 100000 * 100 = 3.0%
        assert result["metrics"]["ctr_pct"] == 3.0

    def test_cvr(self, campaign):
        result = calculate_campaign_metrics(campaign)
        # CVR = 10 / 100 * 100 = 10.0%
        assert result["metrics"]["cvr_pct"] == 10.0

    def test_profit(self, campaign):
        result = calculate_campaign_metrics(campaign)
        assert result["metrics"]["profit"] == 4000.0

    def test_zero_customers(self):
        campaign = {"name": "No Customers", "channel": "display", "spend": 500, "revenue": 0,
                     "impressions": 10000, "clicks": 50, "leads": 5, "customers": 0}
        result = calculate_campaign_metrics(campaign)
        assert result["metrics"]["cpa"] is None
        assert result["metrics"]["cac"] is None

    def test_zero_impressions(self):
        campaign = {"name": "No Impressions", "channel": "email", "spend": 100, "revenue": 500,
                     "impressions": 0, "clicks": 0, "leads": 0, "customers": 0}
        result = calculate_campaign_metrics(campaign)
        assert result["metrics"]["ctr_pct"] is None
        assert result["metrics"]["cpm"] is None

    def test_unprofitable_campaign_flagged(self):
        campaign = {"name": "Loser", "channel": "display", "spend": 1000, "revenue": 200,
                     "impressions": 50000, "clicks": 100, "leads": 5, "customers": 1}
        result = calculate_campaign_metrics(campaign)
        assert any("unprofitable" in f.lower() for f in result["flags"])

    def test_benchmark_assessments_present(self, campaign):
        result = calculate_campaign_metrics(campaign)
        assert "ctr" in result["assessments"]
        assert "benchmark_range" in result["assessments"]["ctr"]


class TestCalculatePortfolioSummary:
    def test_aggregates_totals(self):
        campaigns = [
            calculate_campaign_metrics({
                "name": "A", "channel": "email", "spend": 500, "revenue": 2000,
                "impressions": 50000, "clicks": 1000, "leads": 50, "customers": 5,
            }),
            calculate_campaign_metrics({
                "name": "B", "channel": "paid_search", "spend": 1000, "revenue": 4000,
                "impressions": 100000, "clicks": 3000, "leads": 100, "customers": 10,
            }),
        ]
        summary = calculate_portfolio_summary(campaigns)
        assert summary["total_spend"] == 1500
        assert summary["total_revenue"] == 6000
        assert summary["total_profit"] == 4500
        assert summary["total_customers"] == 15
        assert summary["total_campaigns"] == 2

    def test_channel_summary(self):
        campaigns = [
            calculate_campaign_metrics({
                "name": "A", "channel": "email", "spend": 500, "revenue": 2000,
                "impressions": 50000, "clicks": 1000, "leads": 50, "customers": 5,
            }),
        ]
        summary = calculate_portfolio_summary(campaigns)
        assert "email" in summary["channel_summary"]
        assert summary["channel_summary"]["email"]["spend"] == 500
