from django.shortcuts import render
import re
from collections import defaultdict
from hub.services.models import ComputePlan, VSHNAppCatPrice


def natural_sort_key(name):
    """Extract numeric part from compute plan name for natural sorting"""
    match = re.search(r"compute-std-(\d+)", name)
    return int(match.group(1)) if match else 0


def pricelist(request):
    """Generate comprehensive price list grouped by compute plan groups and service levels"""
    # Check if discount details should be shown
    show_discount_details = request.GET.get("discount_details", "").lower() == "true"

    # Fetch all active compute plans with related data
    compute_plans = (
        ComputePlan.objects.filter(active=True)
        .select_related("cloud_provider", "group")
        .prefetch_related("prices")
        .order_by("group__order", "group__name", "cloud_provider__name")
    )

    # Apply natural sorting for compute plan names
    compute_plans = sorted(
        compute_plans,
        key=lambda x: (
            x.group.order if x.group else 999,  # No group plans at the end
            x.group.name if x.group else "ZZZ",
            x.cloud_provider.name,
            natural_sort_key(x.name),
        ),
    )

    # Fetch all appcat price configurations
    appcat_prices = (
        VSHNAppCatPrice.objects.all()
        .select_related("service", "discount_model")
        .prefetch_related("base_fees", "unit_rates", "discount_model__tiers")
        .order_by("service__name")
    )

    pricing_data_by_group_and_service_level = defaultdict(lambda: defaultdict(list))
    processed_combinations = set()

    # Generate pricing combinations for each compute plan and service
    for plan in compute_plans:
        plan_currencies = set(plan.prices.values_list("currency", flat=True))

        for appcat_price in appcat_prices:
            # Determine units based on variable unit type
            if appcat_price.variable_unit == VSHNAppCatPrice.VariableUnit.RAM:
                units = int(plan.ram)
            elif appcat_price.variable_unit == VSHNAppCatPrice.VariableUnit.CPU:
                units = int(plan.vcpus)
            else:
                continue

            base_fee_currencies = set(
                appcat_price.base_fees.values_list("currency", flat=True)
            )

            service_levels = appcat_price.unit_rates.values_list(
                "service_level", flat=True
            ).distinct()

            for service_level in service_levels:
                unit_rate_currencies = set(
                    appcat_price.unit_rates.filter(
                        service_level=service_level
                    ).values_list("currency", flat=True)
                )

                # Find currencies that exist across all pricing components
                matching_currencies = plan_currencies.intersection(
                    base_fee_currencies
                ).intersection(unit_rate_currencies)

                if not matching_currencies:
                    continue

                for currency in matching_currencies:
                    combination_key = (
                        plan.cloud_provider.name,
                        plan.name,
                        appcat_price.service.name,
                        service_level,
                        currency,
                    )

                    # Skip if combination already processed
                    if combination_key in processed_combinations:
                        continue

                    processed_combinations.add(combination_key)

                    # Get pricing components
                    compute_plan_price = plan.get_price(currency)
                    base_fee = appcat_price.get_base_fee(currency)
                    unit_rate = appcat_price.get_unit_rate(currency, service_level)

                    # Skip if any pricing component is missing
                    if any(
                        price is None
                        for price in [compute_plan_price, base_fee, unit_rate]
                    ):
                        continue

                    # Calculate replica enforcement based on service level
                    if service_level == VSHNAppCatPrice.ServiceLevel.GUARANTEED:
                        replica_enforce = appcat_price.ha_replica_min
                    else:
                        replica_enforce = 1

                    total_units = units * replica_enforce
                    standard_sla_price = base_fee + (total_units * unit_rate)

                    # Apply discount if available
                    discount_breakdown = None
                    if (
                        appcat_price.discount_model
                        and appcat_price.discount_model.active
                    ):
                        discounted_price = (
                            appcat_price.discount_model.calculate_discount(
                                unit_rate, total_units
                            )
                        )
                        sla_price = base_fee + discounted_price
                        discount_savings = standard_sla_price - sla_price
                        discount_percentage = (
                            (discount_savings / standard_sla_price) * 100
                            if standard_sla_price > 0
                            else 0
                        )
                        discount_breakdown = (
                            appcat_price.discount_model.get_discount_breakdown(
                                unit_rate, total_units
                            )
                        )
                    else:
                        sla_price = standard_sla_price
                        discounted_price = total_units * unit_rate
                        discount_savings = 0
                        discount_percentage = 0

                    final_price = compute_plan_price + sla_price
                    service_level_display = dict(VSHNAppCatPrice.ServiceLevel.choices)[
                        service_level
                    ]

                    group_name = plan.group.name if plan.group else "No Group"

                    # Add pricing data to the grouped structure
                    pricing_data_by_group_and_service_level[group_name][
                        service_level_display
                    ].append(
                        {
                            "cloud_provider": plan.cloud_provider.name,
                            "service": appcat_price.service.name,
                            "compute_plan": plan.name,
                            "compute_plan_group": group_name,
                            "compute_plan_group_description": (
                                plan.group.description if plan.group else ""
                            ),
                            "compute_plan_group_node_label": (
                                plan.group.node_label if plan.group else ""
                            ),
                            "vcpus": plan.vcpus,
                            "ram": plan.ram,
                            "cpu_mem_ratio": plan.cpu_mem_ratio,
                            "term": plan.get_term_display(),
                            "currency": currency,
                            "compute_plan_price": compute_plan_price,
                            "variable_unit": appcat_price.get_variable_unit_display(),
                            "units": units,
                            "replica_enforce": replica_enforce,
                            "total_units": total_units,
                            "service_level": service_level_display,
                            "sla_base": base_fee,
                            "sla_per_unit": unit_rate,
                            "sla_price": sla_price,
                            "standard_sla_price": standard_sla_price,
                            "discounted_sla_price": (
                                base_fee + discounted_price
                                if appcat_price.discount_model
                                and appcat_price.discount_model.active
                                else None
                            ),
                            "discount_savings": discount_savings,
                            "discount_percentage": discount_percentage,
                            "discount_breakdown": discount_breakdown,
                            "final_price": final_price,
                            "discount_model": (
                                appcat_price.discount_model.name
                                if appcat_price.discount_model
                                else None
                            ),
                            "has_discount": bool(
                                appcat_price.discount_model
                                and appcat_price.discount_model.active
                            ),
                        }
                    )

    # Order groups correctly, placing "No Group" last
    ordered_groups_intermediate = {}
    all_group_names = list(pricing_data_by_group_and_service_level.keys())

    if "No Group" in all_group_names:
        all_group_names.remove("No Group")
        all_group_names.append("No Group")

    for group_name_key in all_group_names:
        ordered_groups_intermediate[group_name_key] = (
            pricing_data_by_group_and_service_level[group_name_key]
        )

    # Convert defaultdicts to regular dicts for the template
    final_context_data = {}
    for group_key, service_levels_dict in ordered_groups_intermediate.items():
        final_context_data[group_key] = {
            sl_key: list(plans_list)
            for sl_key, plans_list in service_levels_dict.items()
        }

    context = {
        "pricing_data_by_group_and_service_level": final_context_data,
        "show_discount_details": show_discount_details,
    }
    return render(request, "services/pricelist.html", context)
