from decimal import Decimal
from django.test import TestCase
from django.utils import timezone
from datetime import timedelta

from ..models.base import Currency, Term, Unit
from ..models.providers import CloudProvider
from ..models.services import Service
from ..models.pricing import (
    ComputePlan,
    ComputePlanPrice,
    ProgressiveDiscountModel,
    DiscountTier,
    VSHNAppCatPrice,
    VSHNAppCatBaseFee,
    VSHNAppCatUnitRate,
    VSHNAppCatAddon,
    ExternalPricePlans,
)


class PricingEdgeCasesTestCase(TestCase):
    """Test edge cases and error conditions in pricing models"""

    def setUp(self):
        self.cloud_provider = CloudProvider.objects.create(
            name="Test Provider",
            slug="test-provider",
            description="Test cloud provider",
            website="https://test.com",
        )

        self.service = Service.objects.create(
            name="Test Service",
            slug="test-service",
            description="Test service",
            features="Test features",
        )

    def test_discount_tier_validation_overlapping_ranges(self):
        """Test that overlapping discount tiers can be created (business logic may handle conflicts)"""
        discount_model = ProgressiveDiscountModel.objects.create(
            name="Test Discount", active=True
        )

        # Create first tier
        DiscountTier.objects.create(
            discount_model=discount_model,
            min_units=0,
            max_units=20,
            discount_percent=Decimal("5.00"),
        )

        # Create overlapping tier - should be allowed at model level
        # Business logic in calculate_discount should handle this appropriately
        DiscountTier.objects.create(
            discount_model=discount_model,
            min_units=15,
            max_units=30,
            discount_percent=Decimal("10.00"),
        )

        # Should be able to create both tiers
        self.assertEqual(discount_model.tiers.count(), 2)

    def test_discount_calculation_with_zero_units(self):
        """Test discount calculation with zero units"""
        discount_model = ProgressiveDiscountModel.objects.create(
            name="Test Discount", active=True
        )

        DiscountTier.objects.create(
            discount_model=discount_model,
            min_units=0,
            max_units=10,
            discount_percent=Decimal("0.00"),
        )

        result = discount_model.calculate_discount(Decimal("10.00"), 0)
        self.assertEqual(result, 0)

    def test_discount_calculation_with_very_large_numbers(self):
        """Test discount calculation with very large numbers"""
        discount_model = ProgressiveDiscountModel.objects.create(
            name="Test Discount", active=True
        )

        DiscountTier.objects.create(
            discount_model=discount_model,
            min_units=0,
            max_units=None,
            discount_percent=Decimal("10.00"),
        )

        large_units = 1000000
        base_rate = Decimal("0.001")

        result = discount_model.calculate_discount(base_rate, large_units)
        expected = base_rate * Decimal("0.9") * large_units
        self.assertEqual(result, expected)

    def test_price_calculation_with_inactive_discount_model(self):
        """Test price calculation when discount model is inactive"""
        discount_model = ProgressiveDiscountModel.objects.create(
            name="Inactive Discount", active=False  # Inactive
        )

        DiscountTier.objects.create(
            discount_model=discount_model,
            min_units=0,
            max_units=None,
            discount_percent=Decimal("50.00"),  # Large discount
        )

        price_config = VSHNAppCatPrice.objects.create(
            service=self.service,
            variable_unit=VSHNAppCatPrice.VariableUnit.RAM,
            term=Term.MTH,
            discount_model=discount_model,
        )

        VSHNAppCatBaseFee.objects.create(
            vshn_appcat_price_config=price_config,
            currency=Currency.CHF,
            service_level=VSHNAppCatPrice.ServiceLevel.GUARANTEED,
            amount=Decimal("50.00"),
        )

        VSHNAppCatUnitRate.objects.create(
            vshn_appcat_price_config=price_config,
            currency=Currency.CHF,
            service_level=VSHNAppCatPrice.ServiceLevel.GUARANTEED,
            amount=Decimal("10.0000"),
        )

        result = price_config.calculate_final_price(
            Currency.CHF, VSHNAppCatPrice.ServiceLevel.GUARANTEED, 5
        )

        # Should ignore discount since model is inactive
        expected_total = Decimal("50.00") + (Decimal("10.0000") * 5)
        self.assertEqual(result["total_price"], expected_total)

    def test_addon_with_missing_prices(self):
        """Test addon behavior when price data is missing"""
        price_config = VSHNAppCatPrice.objects.create(
            service=self.service,
            variable_unit=VSHNAppCatPrice.VariableUnit.RAM,
            term=Term.MTH,
        )

        # Create addon but no corresponding price objects
        addon = VSHNAppCatAddon.objects.create(
            vshn_appcat_price_config=price_config,
            name="Incomplete Addon",
            addon_type=VSHNAppCatAddon.AddonType.BASE_FEE,
            mandatory=True,
        )

        # Should return None when price doesn't exist
        # For BASE_FEE addons, service_level is required
        price = addon.get_price(Currency.CHF, service_level="standard")
        self.assertIsNone(price)

    def test_compute_plan_with_validity_dates(self):
        """Test compute plan with validity date ranges"""
        now = timezone.now()
        past_date = now - timedelta(days=30)
        future_date = now + timedelta(days=30)

        # Create plan that is not yet valid
        future_plan = ComputePlan.objects.create(
            name="Future Plan",
            vcpus=4.0,
            ram=8.0,
            cpu_mem_ratio=0.5,
            cloud_provider=self.cloud_provider,
            valid_from=future_date,
            valid_to=None,
        )

        # Create plan that has expired
        expired_plan = ComputePlan.objects.create(
            name="Expired Plan",
            vcpus=2.0,
            ram=4.0,
            cpu_mem_ratio=0.5,
            cloud_provider=self.cloud_provider,
            valid_from=past_date,
            valid_to=past_date + timedelta(days=10),
        )

        # Plans should still be created and queryable
        self.assertTrue(ComputePlan.objects.filter(name="Future Plan").exists())
        self.assertTrue(ComputePlan.objects.filter(name="Expired Plan").exists())

    def test_decimal_precision_edge_cases(self):
        """Test decimal precision in price calculations"""
        price_config = VSHNAppCatPrice.objects.create(
            service=self.service,
            variable_unit=VSHNAppCatPrice.VariableUnit.RAM,
            term=Term.MTH,
        )

        VSHNAppCatBaseFee.objects.create(
            vshn_appcat_price_config=price_config,
            currency=Currency.CHF,
            service_level=VSHNAppCatPrice.ServiceLevel.GUARANTEED,
            amount=Decimal("0.01"),  # Very small base fee
        )

        VSHNAppCatUnitRate.objects.create(
            vshn_appcat_price_config=price_config,
            currency=Currency.CHF,
            service_level=VSHNAppCatPrice.ServiceLevel.GUARANTEED,
            amount=Decimal("0.0001"),  # Very small unit rate
        )

        result = price_config.calculate_final_price(
            Currency.CHF,
            VSHNAppCatPrice.ServiceLevel.GUARANTEED,
            1000,  # Large quantity
        )

        expected_total = Decimal("0.01") + (Decimal("0.0001") * 1000)
        self.assertEqual(result["total_price"], expected_total)

    def test_external_price_comparison_model(self):
        """Test ExternalPricePlans model functionality"""
        compute_plan = ComputePlan.objects.create(
            name="Comparison Plan",
            vcpus=2.0,
            ram=4.0,
            cpu_mem_ratio=0.5,
            cloud_provider=self.cloud_provider,
        )

        external_price = ExternalPricePlans.objects.create(
            plan_name="Competitor Plan",
            description="Competitor offering",
            cloud_provider=self.cloud_provider,
            service=self.service,
            currency=Currency.USD,
            term=Term.MTH,
            amount=Decimal("99.99"),
            vcpus=2.0,
            ram=4.0,
            storage=50.0,
        )

        external_price.compare_to.add(compute_plan)

        self.assertEqual(
            str(external_price), "Test Provider - Test Service - Competitor Plan"
        )
        self.assertTrue(external_price.compare_to.filter(id=compute_plan.id).exists())

    def test_unique_constraints_enforcement(self):
        """Test that unique constraints are properly enforced"""
        compute_plan = ComputePlan.objects.create(
            name="Test Plan",
            vcpus=2.0,
            ram=4.0,
            cpu_mem_ratio=0.5,
            cloud_provider=self.cloud_provider,
        )

        # Create first price
        ComputePlanPrice.objects.create(
            compute_plan=compute_plan, currency=Currency.CHF, amount=Decimal("100.00")
        )

        # Try to create duplicate - should raise IntegrityError
        with self.assertRaises(Exception):  # IntegrityError or ValidationError
            ComputePlanPrice.objects.create(
                compute_plan=compute_plan,
                currency=Currency.CHF,
                amount=Decimal("200.00"),
            )

    def test_addon_ordering_and_active_filtering(self):
        """Test addon ordering and active status filtering"""
        price_config = VSHNAppCatPrice.objects.create(
            service=self.service,
            variable_unit=VSHNAppCatPrice.VariableUnit.RAM,
            term=Term.MTH,
        )

        # Create addons with different orders and active status
        addon1 = VSHNAppCatAddon.objects.create(
            vshn_appcat_price_config=price_config,
            name="Third Addon",
            addon_type=VSHNAppCatAddon.AddonType.BASE_FEE,
            order=3,
            active=True,
        )

        addon2 = VSHNAppCatAddon.objects.create(
            vshn_appcat_price_config=price_config,
            name="First Addon",
            addon_type=VSHNAppCatAddon.AddonType.BASE_FEE,
            order=1,
            active=True,
        )

        addon3 = VSHNAppCatAddon.objects.create(
            vshn_appcat_price_config=price_config,
            name="Inactive Addon",
            addon_type=VSHNAppCatAddon.AddonType.BASE_FEE,
            order=2,
            active=False,
        )

        # Test ordering
        ordered_addons = price_config.addons.all().order_by("order", "name")
        self.assertEqual(ordered_addons[0], addon2)  # order=1
        self.assertEqual(ordered_addons[1], addon3)  # order=2
        self.assertEqual(ordered_addons[2], addon1)  # order=3

        # Test active filtering
        active_addons = price_config.addons.filter(active=True)
        self.assertEqual(active_addons.count(), 2)
        self.assertNotIn(addon3, active_addons)
