import base64
import io
import httpx
from typing import Dict, Any
from openai import AsyncOpenAI
from datetime import datetime, timedelta

from app.configs.settings import settings
from app.utils.constants import get_hotel_details

async def build_other_hotels(current_hotel_id: str) -> str:
    hotels = []
    HOTEL_INFO = await get_hotel_details()
    for hotel_id, info in HOTEL_INFO.items():
        if hotel_id == current_hotel_id:
            continue

        hotels.append(f"""
<OUR-OTHER-HOTELS>
    <NAME>{info['hotel_name']}</NAME>
    <ADDRESS>{info['hotel_address']}</ADDRESS>
    <EMAIL>{info['hotel_email']}</EMAIL>
    <PHONE>{info['hotel_phone']}</PHONE>
    <HOTEL-ID>{hotel_id}</HOTEL-ID>
</OUR-OTHER-HOTELS>
""")

    return "\n".join(hotels)

def compact_cart_for_llm(cart_data: Dict[str, Any]) -> Dict[str, Any]:
    """
    Convert raw cart payload into compact LLM-friendly structure.
    Removes unnecessary/internal/system fields to save tokens.
    """

    compact_items = []
    grand_total = 0.0
    total_deposit_amount = 0.0

    for _, items in cart_data.items():

        if not items:
            continue

        item = items[0]

        compact_item = {
            "type": item.get("cart_type"),
            "name": item.get("fe_display_product_name")
                    or item.get("cart_product_name"),
            "quantity": int(item.get("service_quantity", 1)),
            "total": float(item.get("grand_total", 0)),
        }

        # Reservation specific fields
        if item.get("cart_type") == "reservation":
            compact_item.update({
                "hotel": item.get("cart_room_hotel_name"),
                "room": item.get("room_type_name"),
                "check_in": item.get("room_stay_from"),
                "check_out": item.get("room_stay_to"),
                "guests": int(item.get("room_stay_guest_count", 0)),
                "rate_plan": item.get("rate_plan_name"),
                "subtotal": float(item.get("subtotal", 0)),
            })

        # POS / add-on item fields
        elif item.get("cart_type") == "pos":
            compact_item.update({
                "attached_room": item.get("attached_room_name"),
                "subtotal": float(item.get("subtotal", 0)),
            })

        # Include taxes only if useful
        taxes = []
        for tax in item.get("tax_info", []):
            taxes.append({
                "name": tax.get("tax_name"),
                "amount": float(tax.get("tax_amount", 0))
            })

        if taxes:
            compact_item["taxes"] = taxes

        # Optional important descriptions
        if item.get("description"):
            compact_item["description"] = clean_html(
                item.get("description")
            )

        compact_items.append(compact_item)

        grand_total += float(item.get("grand_total", 0))
        total_deposit_amount += float(item.get("total_deposit_amount", 0))

    return {
        "items": compact_items,
        "cart_items_count": len(compact_items),
        "grand_total": round(grand_total, 2),
        "total_deposit_amount": round(total_deposit_amount, 2)
    }


def clean_html(text: str) -> str:
    """
    Remove simple HTML tags.
    """
    import re

    if not text:
        return ""

    clean = re.sub(r"<.*?>", "", text)
    clean = re.sub(r"\s+", " ", clean).strip()

    return clean

async def is_booking_allowed(checkindate: str, checkoutdate: str, hotel_id: str, sub_hotel_id: str, hotel_ids: list) -> bool:
    """
    checkindate / checkoutdate format: MM-DD-YYYY
    Returns True if booking is allowed, else False.
    Prints warning message before returning False.
    """

    # Validate date format
    try:
        checkin = datetime.strptime(checkindate, "%m-%d-%Y").date()
        checkout = datetime.strptime(checkoutdate, "%m-%d-%Y").date()
    except ValueError:
        return {'status': False, 'message': "Something went wrong. Please try again."}

    if checkout <= checkin:
        return {'status': False, 'message': "The checkout date must be later than the check-in date. Please select a different checkout date."}

    if checkin == checkout:
        return {'status': False, 'message': "Check-in and checkout dates cannot be the same. Please select a different checkout date."}

    url = f"{settings.LS_API_URL}frontend/Searchresults/getPriceMlsStopSell"

    headers = {
        "hotel_id": hotel_id,
        "sub_hotel_id": sub_hotel_id,
    }

    # YYYY-MM-DD
    checkindate_for_payload = datetime.strptime(checkindate, "%m-%d-%Y").strftime("%Y-%m-%d")
    checkoutdate_for_payload = datetime.strptime(checkoutdate, "%m-%d-%Y").strftime("%Y-%m-%d")

    payload = {
        "first": checkindate_for_payload,
        "last": checkoutdate_for_payload,
        "promo": "",
        "sub_hotel_id": sub_hotel_id if not len(hotel_ids) else hotel_ids[0],
        "fromSuitesPage": True,
        "ibeV2": True
    }

    try:
        async with httpx.AsyncClient(timeout=60.0) as client:
            response = await client.post(url, json=payload, headers=headers)
            response.raise_for_status()
            data = response.json()
    except Exception as e:
        print(f"Warning: API request failed: {e}")
        return {'status': False, 'message': "Something went wrong. Please try again."}

    # -----------------------------
    # STOP SELL CHECK
    # -----------------------------
    stop_sell_map = {}
    for item in data.get("stopSell", []):
        dt = datetime.strptime(item["date"], "%m/%d/%Y").date()
        stop_sell_map[dt] = item["value"]

    # check all stay nights (checkin inclusive, checkout exclusive)
    current = checkin
    while current < checkout:
        if stop_sell_map.get(current) == 1:
            if current == checkin:
                return {
                    'status': False,
                    'message': f"Rooms are not available for check-in on {current}. Please select a different check-in date."
                }
            else:
                return {
                    'status': False,
                    'message': f"Rooms are not available on {current}, which falls within your selected stay dates. Please choose different dates."
                }
        current += timedelta(days=1)

    # -----------------------------
    # MIN STAY CHECK
    # -----------------------------
    min_stay = data.get("minStay", {})
    checkin_key = checkin.strftime("%m/%d/%Y")

    required_nights = min_stay.get(checkin_key, 0)

    try:
        required_nights = int(required_nights)
    except (ValueError, TypeError):
        required_nights = 0

    actual_nights = (checkout - checkin).days

    if required_nights > 0 and actual_nights < required_nights:
        return {
            'status': False,
            'message': f"Bookings starting on {checkindate} require a minimum stay of {required_nights} night(s), but your selected stay is {actual_nights} night(s). Please choose a longer stay."
        }

    return {'status': True, 'message': ""}

async def transcribe_audio(audio_file_base64: str) -> str:
    client = AsyncOpenAI(api_key=settings.OPENAI_API_KEY)

    # Remove the data URL prefix
    if "," in audio_file_base64:
        _, audio_data = audio_file_base64.split(",", 1)
    else:
        audio_data = audio_file_base64

    audio_bytes = base64.b64decode(audio_data)

    audio_file = io.BytesIO(audio_bytes)
    audio_file.name = "audio.webm"   # important so SDK knows filename

    transcript = await client.audio.transcriptions.create(
        model="gpt-4o-transcribe",
        file=audio_file,
    )

    return transcript.text