"""Game status, discounts and effective price calculation."""
import re
from datetime import datetime
from flask import request

from nexora.core import app
from nexora.database.connection import query
from nexora.utils.formatting import parse_dt


def game_status(game, registration_open=None):
    """Return (is_open, label) for a game's registration window."""
    if registration_open is None:
        row = query("SELECT registration_open FROM settings WHERE id = 1", one=True)
        registration_open = row["registration_open"] if row else 1

    if not registration_open:
        return False, "Closed"

    now = datetime.now()
    start = parse_dt(game["reg_from"] if "reg_from" in game.keys() else "")
    end = parse_dt(game["reg_to"] if "reg_to" in game.keys() else "")

    if start and now < start:
        return False, "Opens Soon"
    if end and now > end:
        return False, "Closed"
    return True, "Open"


def discount_active(game):
    """A discount is active when it has a valid percentage and its optional window matches now."""
    if not game:
        return False
    pct = discount_pct_value(game)
    if pct <= 0 or pct > 100:
        return False

    now = datetime.now()
    start = parse_dt(game["discount_from"] if "discount_from" in game.keys() else "")
    end = parse_dt(game["discount_to"] if "discount_to" in game.keys() else "")
    if start and now < start:
        return False
    if end and now > end:
        return False
    return True


def get_discount_type(game):
    if not game:
        return "percentage"
    val = game["discount_type"] if "discount_type" in game.keys() else None
    return str(val or "percentage").strip().lower()

def discount_pct_value(game):
    """Return the configured discount percent, safely ignoring game names like 'Tekken 8'."""
    if not game:
        return 0
    
    if "discount_pct" in game.keys():
        val = str(game["discount_pct"] or "").strip()
        if val:
            found = re.search(r"^\d+(?:\.\d+)?", val)
            if found:
                try:
                    return float(found.group(0))
                except ValueError:
                    pass
                
    if "discount_label" in game.keys():
        lbl = str(game["discount_label"] or "").strip()
        if lbl:
            # Look for numbers directly followed by % or "off" to avoid "Tekken 8" false positives
            found = re.search(r"(\d+(?:\.\d+)?)\s*(?:%|% off|percent|off|discount)\b", lbl, re.IGNORECASE)
            if found:
                try:
                    return float(found.group(1))
                except ValueError:
                    pass
            # Fallback for purely numeric labels "20" (legacy data)
            elif re.fullmatch(r"\d+(?:\.\d+)?", lbl):
                try:
                    return float(lbl)
                except ValueError:
                    pass
                
    return 0


def discount_label_text(game):
    pct = discount_pct_value(game)
    dtype = get_discount_type(game)
    label = str(game["discount_label"] if game and "discount_label" in game.keys() else "").strip()
    if pct and (not label or re.fullmatch(r"\d+(?:\.\d+)?%?", label) or re.fullmatch(r"\d+(?:\.\d+)?", label)):
        if dtype == "fixed":
            return f"Flat Rs. {pct:g} Off"
        else:
            return f"{pct:g}% Discount"
    if label and "%" not in label and pct and dtype != "fixed":
        return f"{label} ({pct:g}% Discount)"
    return label


def discounted_price(price_str, pct):
    return disc_price_filter(price_str, pct)


def registration_effective_price(row, entry_type, member_count):
    is_free = (row["is_free"] or "") == "1" if "is_free" in row.keys() else False
    if is_free:
        return {"original": "Rs. 0", "discounted": "Rs. 0", "active": False}
    if entry_type == "group":
        size_key = f"price_for_{member_count}"
        original = row[size_key] if size_key in row.keys() and row[size_key] else row["group_price"]
    else:
        original = row["individual_price"]
    pct = discount_pct_value(row) if discount_active(row) else 0
    dtype = get_discount_type(row)
    return disc_price_filter(original, pct, dtype)


def game_price_for_size(game, size):
    if not game:
        return ""
    if "is_free" in game.keys() and str(game["is_free"]) == "1":
        return "Rs. 0"
    if int(size or 1) <= 1:
        return game["individual_price"] if "individual_price" in game.keys() else ""
    key = f"price_for_{int(size)}"
    if key in game.keys() and game[key]:
        return game[key]
    return game["group_price"] if "group_price" in game.keys() else ""


@app.template_global("effective_max_members")
def effective_max_members(game):
    if not game:
        return 1
    try:
        max_m = int(game["max_members"] or 1) if "max_members" in game.keys() else 1
    except (TypeError, ValueError):
        max_m = 1
    return max_m


def form_member_bounds():
    try:
        min_m = max(1, min(4, int(request.form.get("min_members", 1) or 1)))
    except (TypeError, ValueError):
        min_m = 1
    try:
        max_m = max(1, min(4, int(request.form.get("max_members", 1) or 1)))
    except (TypeError, ValueError):
        max_m = 1
    # Respect explicitly set max_members from form; don't auto-expand based on prices
    return min(min_m, max_m), max_m


@app.template_filter("disc_price")
def disc_price_filter(price_str, pct, discount_type="percentage"):
    from decimal import Decimal, InvalidOperation
    """Apply a discount percentage to a price string.

    Returns {"original", "discounted", "active"} where BOTH values are
    canonical single prices ("Rs. 1,200" / "Rs. 960"). Dirty inputs that
    accidentally contain several numbers ("Rs. 1,200 960") are reduced to
    their first number so concatenated prices can never reach the UI again.
    """
    import re as _re

    def _canonical(text):
        """Normalize any price-ish text to 'Prefix Amount' using its first number."""
        s = str(text or "").strip()
        if not s:
            return ""
        m = _re.search(r"\d[\d,]*(?:\.\d+)?", s)
        if not m:
            return s
        # Keep abbreviation dots ("Rs.") â€” strip only separator junk.
        prefix = _re.sub(r"[\s;:/\\-]+$", "", s[: m.start()]).strip()
        prefix = _re.sub(r"\s+", " ", prefix)
        if not prefix.strip():
            prefix = "Rs."
        amount = f"{float(m.group(0).replace(',', '')):,.0f}"
        return f"{prefix} {amount}"

    original_text = _canonical(price_str)
    try:
        pct = float(pct or 0)
    except (ValueError, TypeError):
        pct = 0
    m = _re.search(r"\d[\d,]*(?:\.\d+)?", str(price_str or ""))
    if not m or pct <= 0 or pct > 100:
        return {"original": original_text, "discounted": original_text, "active": False}
    val = float(m.group(0).replace(",", ""))
    if discount_type == "fixed":
        discounted = max(0, val - pct)
    else:
        discounted = val * (1 - pct / 100)
        
    if discounted < 0:
        return {"original": original_text, "discounted": original_text, "active": False}
    # Reuse the same currency prefix as the original ("Rs." etc.), else none.
    # NOTE: keep a trailing dot on abbreviations like "Rs." â€” only strip
    # genuine separator junk (spaces/semicolons/slashes).
    pm = _re.match(r"^\D*?(?=\d)", str(price_str).strip())
    prefix = _re.sub(r"[\s;:/\\-]+$", "", pm.group(0)) if pm else ""
    prefix = _re.sub(r"\s+", " ", prefix).strip()
    if not prefix.strip():
        prefix = "Rs."
    formatted = f"{prefix} {discounted:,.0f}"
    return {"original": original_text, "discounted": formatted, "active": True}
