from datetime import datetime
from decimal import Decimal, ROUND_HALF_UP


def D(value):
    """Helper: Always return a properly rounded Decimal."""
    try:
        return Decimal(str(value)).quantize(Decimal("0.01"), rounding=ROUND_HALF_UP)
    except Exception:
        return Decimal("0.00")


# ======================================================
#  FESTIVAL DISCOUNT (Dynamic)
# ======================================================
def apply_festival_discount(price, event, config):
    if not isinstance(price, Decimal):
        price = D(price)

    festival_name = config.get("festival_name", None)
    festival_percent = config.get("festival_percent", 0)

    # Match festival event only if event name equals current active festival
    if event and festival_name and event == festival_name:
        discount = D(festival_percent) / D(100)
        reason = f"Festival: {festival_name}"
    else:
        discount = D("0")
        reason = None

    discounted_price = price * (D("1") - discount)

    return discounted_price, discount * 100, reason


# ======================================================
#  WEEKEND DISCOUNT (Dynamic)
# ======================================================
def apply_weekend_discount(price, config):
    if not isinstance(price, Decimal):
        price = D(price)

    weekend_percent = config.get("weekend_percent", 0)
    weekend_discount = D(weekend_percent) / D(100)

    # Saturday = 5, Sunday = 6
    if datetime.today().weekday() in [5, 6]:
        discounted = price * (D("1") - weekend_discount)
        return discounted, weekend_discount * 100, "Weekend Offer"

    return price, D("0"), None


# ======================================================
#  LONG STAY DISCOUNT (Dynamic)
# ======================================================
def apply_longstay_discount(price, days, config):
    if not isinstance(price, Decimal):
        price = D(price)

    ls3 = D(config.get("longstay_3_days", 0))
    ls7 = D(config.get("longstay_7_days", 0))

    discount = D("0")
    reason = None

    if days >= 7:
        discount = ls7 / D(100)
        reason = "Long-Stay (7+ days)"
    elif days >= 3:
        discount = ls3 / D(100)
        reason = "Long-Stay (3+ days)"

    discounted_price = price * (D("1") - discount)

    return discounted_price, discount * 100, reason


# ======================================================
#  FINAL COMBINED CALCULATION (Dynamic)
# ======================================================
def calculate_final_price(base_price, event=None, days=1, config=None):
    """
    Dynamic discounts using values passed in config dict.
    """

    if config is None:
        config = {}

    if not isinstance(base_price, Decimal):
        base_price = D(base_price)

    # Step 1: Festival
    f_price, f_percent, f_reason = apply_festival_discount(base_price, event, config)

    # Step 2: Weekend
    w_price, w_percent, w_reason = apply_weekend_discount(f_price, config)

    # Step 3: Long Stay
    ls_price, ls_percent, ls_reason = apply_longstay_discount(w_price, days, config)

    # Final total discount calculations
    final_price = ls_price
    total_discount_amount = base_price - final_price

    try:
        total_discount_percent = (total_discount_amount / base_price) * 100
    except Exception:
        total_discount_percent = D("0")

    # Collect reasons
    reasons = [r for r in [f_reason, w_reason, ls_reason] if r]
    discount_reason = " + ".join(reasons) if reasons else None

    return {
        "final_price": float(round(final_price, 2)),
        "total_discount_percent": float(round(total_discount_percent, 1)),
        "total_discount_amount": float(round(total_discount_amount, 2)),
        "discount_reason": discount_reason
    }
