import re
import httpx
from copy import deepcopy
from app.configs.settings import settings
import logging

logger = logging.getLogger(__name__)

# Internal fields that provide no value to an AI assistant
REMOVE_KEYS = {
    "room_stay_id",
    "reserv_id",
    "customer_id",
    "customerId",
    "travellerId",
    "customer_traveller_id",
    "current_billing",
    "product_id",
    "type_id",
    "policy_id",
    "sub_hotel_id",
    "tax_id",
    "res_tax_id",
    "created_by_user",
    "products_added_while_create",
    "room_number_locked_indicator",
    "source_of_creation",
    "auto_added",
    "collect_which",
    "siteminder_id",
    "selectedRatePlanId",
}

# Sensitive fields
SENSITIVE_KEYS = {
    "card_number",
    "credit_card",
    "card",
    "cc_number",
    "cvv",
    "cvc",
    "expiry",
    "expiration",
    "token",
    "payment_token",
    "auth_token",
    "access_token",
    "refresh_token",
    "password",
    "secret",
    "pin",
    "ssn",
}

# Keys that are almost always duplicated / internal
REMOVE_DUPLICATE_SECTIONS = {
    "reservation_data",  # same data exists in reservation
}


def _looks_sensitive(value):
    if not isinstance(value, str):
        return False

    # Possible raw credit card number
    digits = re.sub(r"\D", "", value)
    if 13 <= len(digits) <= 19:
        return True

    return False


def _clean(obj):
    if isinstance(obj, dict):
        cleaned = {}

        for k, v in obj.items():

            # remove duplicate top-level sections
            if k in REMOVE_DUPLICATE_SECTIONS:
                continue

            if k in REMOVE_KEYS:
                continue

            if k.lower() in SENSITIVE_KEYS:
                continue

            if _looks_sensitive(v):
                continue

            value = _clean(v)

            # remove empty values
            if value in (
                None,
                "",
                [],
                {},
            ):
                continue

            cleaned[k] = value

        return cleaned

    elif isinstance(obj, list):
        result = []

        seen = set()

        for item in obj:
            item = _clean(item)

            if item in (None, "", {}, []):
                continue

            # remove duplicate objects
            marker = repr(item)
            if marker in seen:
                continue

            seen.add(marker)
            result.append(item)

        return result

    return obj


def clean_reservation_payload(payload: dict) -> dict:
    """
    Clean reservation payload before sending to an LLM.

    - removes internal IDs
    - removes sensitive data
    - removes empty values
    - removes duplicate sections
    - preserves guest-facing reservation information
    """
    payload = deepcopy(payload)

    cleaned = _clean(payload)

    # reservation_data duplicates reservation
    if (
        "reservation" in cleaned
        and "reservation_data" in cleaned
    ):
        cleaned.pop("reservation_data", None)

    # reservation.overalltotals duplicates overall_totals
    reservation = cleaned.get("reservation")
    if isinstance(reservation, dict):
        reservation.pop("overalltotals", None)

        # resortFeePos already exists inside pos[]
        reservation.pop("resortFeePos", None)

    return cleaned

async def get_reservation(confirmation_number: str, email: str, hotel_id: str, sub_hotel_id: str):
    try:
        async with httpx.AsyncClient(timeout=60.0) as client:
            check = await client.post(
                settings.LS_API_URL + "frontend/Reservations/checkValidConfEmail",
                json={
                    "data": {
                        "confirmation": confirmation_number,
                        "email": email,
                        "hotel_id": 1
                    }
                },
                headers={
                    "hotel_id": hotel_id,
                    "sub_hotel_id": sub_hotel_id,
                }
            )
            if check.json().get("status", "") == "error":
                return {"error": "Reservation not found. Confirmation number (Itenrary) or email is incorrect."}

            response = await client.post(
                settings.LS_API_URL + "frontend/Reservations/loadOrderInfo",
                json={
                    "confirmation": confirmation_number,
                    "get_payment_data": False
                },
                headers={
                    "hotel_id": hotel_id,
                    "sub_hotel_id": sub_hotel_id,
                })
            data = response.json()
            if data.get("status", "") == "success":
                return clean_reservation_payload(data.get("data"))
            else:
                return {"error": "Reservation not found. Confirmation number (Itenrary) or email is incorrect."}
    except Exception as e:
        logger.error(f"Error getting reservation: {e}")
        return {"error": "Error getting reservation. Please try again later."}