import requests
from requests.auth import HTTPBasicAuth
import json
from django.conf import settings
from datetime import datetime, timedelta, timezone
from pprint import pprint

# In-memory token cache
_token_cache = {}

def get_ohip_token(
    host_name: str = settings.OHIP_HOST,
    client_id: str = settings.OHIP_CLIENT_ID,
    client_secret: str = settings.OHIP_CLIENT_SECRET,
    app_key: str = settings.OHIP_APP_KEY,
    grant_type: str = settings.OHIP_GRANT_TYPE,
    username: str = settings.OHIP_USERNAME,
    password: str = settings.OHIP_PASSWORD,
    enterprise_id: str = None,
    scope: str = None,
    force_refresh: bool = False
) -> str:
    """
    Retrieve OAuth token from OHIP using either password or client_credentials grant.
    """
    
    print("== DEBUG OHIP CREDS ==")
    print(f"Host: {host_name}")
    print(f"Client ID: {client_id}")
    print(f"Client Secret: {client_secret}")
    print(f"App Key: {app_key}")
    print(f"Grant Type: {grant_type}")
    print(f"Username: {username}")
    print(f"Password: {password}")

    cache_key = f"{host_name}_{client_id}_{grant_type}"
    now = datetime.now(timezone.utc)

    if not force_refresh and cache_key in _token_cache:
        token_info = _token_cache[cache_key]
        if token_info["expires_at"] > now:
            return token_info["token"]

    url = f"{host_name.rstrip('/')}/oauth/v1/tokens"
    headers = {
        "Content-Type": "application/x-www-form-urlencoded",
        "x-app-key": app_key,
    }
    if enterprise_id:
        headers["enterpriseId"] = enterprise_id

    auth = HTTPBasicAuth(client_id, client_secret)
    data = {"grant_type": grant_type}

    if grant_type == "password":
        if not username or not password:
            raise ValueError("Username and password are required for 'password' grant.")
        data.update({"username": username, "password": password})
    elif grant_type == "client_credentials":
        if scope:
            data["scope"] = scope
    else:
        raise ValueError("grant_type must be either 'password' or 'client_credentials'.")

    response = requests.post(url, headers=headers, data=data, auth=auth)

    if response.status_code == 200:
        token_data = response.json()
        access_token = token_data.get("access_token")
        expires_in = int(token_data.get("expires_in", 3600))
        _token_cache[cache_key] = {
            "token": access_token,
            "expires_at": now + timedelta(seconds=expires_in - 60)
        }
        return access_token
    else:
        raise Exception(f"Failed to get token: {response.status_code} - {response.text}")

class OHIPTokenManager:
    def __init__(self):
        self.token = None
        self.expiry = datetime.now(timezone.utc)

    def get_token(self):
        if not self.token or datetime.now(timezone.utc) >= self.expiry:
            print("🔁 Refreshing OHIP token...")
            self.token = get_ohip_token(force_refresh=True)
            self.expiry = datetime.now(timezone.utc) + timedelta(seconds=3600 - 120)
        return self.token

def get_valid_token():
    return OHIPTokenManager().get_token()

def create_reservation_inline_guest(
    guest_first_name: str,
    guest_last_name: str,
    arrival_date: str,
    departure_date: str,
    token: str, # Automatically fetches token
    host: str = settings.OHIP_HOST, # Default host
    app_key: str = settings.OHIP_APP_KEY,   # Default app key
    hotel_id: str = settings.OHIP_HOTEL_ID, # Default hotel ID
    room_type: str = settings.OHIP_ROOM_TYPE,  # Default room type
    rate_plan_code: str = settings.OHIP_RATE_PLAN_CODE,  # Default rate plan code
    guarantee_code: str = settings.OHIP_GUARANTEE_CODE,  # Default guarantee code
    market_code: str = settings.OHIP_MARKET_CODE,  # Default market code
    source_code: str = settings.OHIP_SOURCE_CODE,  # Default source code
    payment_method: str = settings.OHIP_PAYMENT_METHOD  # Default payment method
):
    url = f"{host}/rsv/v1/hotels/{hotel_id}/reservations"
    headers = {
        "Authorization": f"Bearer {token}",
        "x-app-key": app_key,
        "x-hotelid": hotel_id,
        "Content-Type": "application/json"
    }

    payload = {
        "reservations": {
            "reservation": [
                {
                    "sourceOfSale": {
                        "sourceType": "PMS",
                        "sourceCode": hotel_id
                    },
                    "roomStay": {
                        "roomRates": [
                            {
                                "roomType": room_type,
                                "ratePlanCode": rate_plan_code,
                                "start": arrival_date,
                                "end": departure_date,
                                "marketCode": market_code,
                                "sourceCode": source_code,
                                "pseudoRoom": False,
                                "roomTypeCharged": room_type,
                            }
                        ],
                        "arrivalDate": arrival_date,
                        "departureDate": departure_date,
                        "guarantee": {
                            "guaranteeCode": guarantee_code,
                        },
                    },
                    "reservationGuests": [
                        {
                            "profileInfo": {
                                "profile": {
                                    "customer": {
                                        "personName": [
                                            {
                                                "givenName": guest_first_name,
                                                "surname": guest_last_name,
                                                "nameType": "Primary"
                                            },
                                            {
                                                "nameType": "External"
                                            }
                                        ],
                                        "language": "E"
                                    },
                                    "profileType": "Guest"
                                }
                            },
                            "primary": True
                        }
                    ],
                    "reservationPaymentMethods": [
                        {
                            "paymentMethod": payment_method,
                            "folioView": "1"
                        }
                    ],
                    "hotelId": hotel_id,
                    "roomStayReservation": True,
                }
            ]
        }
    }

    response = requests.post(url, headers=headers, json=payload)
    if response.status_code == 201:
        location = response.headers.get("Location")
        reservation_id = location.rsplit("/", 1)[-1] if location else None

        # Try to extract confirmation number from JSON body
        try:
            body = response.json()
            links = body.get("links", [])
            confirmation_number = None
            for link in links:
                href = link.get("href", "")
                if "confirmationNumberList=" in href:
                    confirmation_number = href.split("confirmationNumberList=")[-1]
                    break
        except Exception:
            confirmation_number = None

        return {
            "status": "success",
            "reservation_id": reservation_id,
            "confirmation_number": confirmation_number,
            "location": location,
            "response_body": body
        }
    else:
        return {
            "status": "error",
            "code": response.status_code,
            "message": response.text,
            "response_body": response.text  # 👈 will show the raw error JSON or text
        }

ROOM_TYPE_LIST = ",".join([
    settings.OHIP_ROOM_TYPE1,
    settings.OHIP_ROOM_TYPE2,
    settings.OHIP_ROOM_TYPE3,
    settings.OHIP_ROOM_TYPE4,
    settings.OHIP_ROOM_TYPE5,
    settings.OHIP_ROOM_TYPE6,
    settings.OHIP_ROOM_TYPE7,
    settings.OHIP_ROOM_TYPE8,
    settings.OHIP_ROOM_TYPE9,
])

def get_inventory_statistics_with_roomtype_list(
    token=None,
    host=settings.OHIP_HOST,
    app_key=settings.OHIP_APP_KEY,
    hotel_id=settings.OHIP_HOTEL_ID,
    start_date=None,
    end_date=None
):
    if token is None:
        token = get_valid_token()

    if start_date is None:
        start_date = datetime.today().strftime("%Y-%m-%d")
    if end_date is None:
        end_date = (datetime.today() + timedelta(days=27)).strftime("%Y-%m-%d")

    url = f"{host}/inv/v1/hotels/{hotel_id}/inventoryStatistics"
    headers = {
        "Authorization": f"Bearer {token}",
        "x-app-key": app_key,
        "x-hotelid": hotel_id
    }
    params = [
        ("reportCode", "RoomsAvailabilitySummary"),
        ("dateRangeStart", start_date),
        ("dateRangeEnd", end_date),
        ("parameterName", "RoomTypeWildCardList"),
        ("parameterValue", ROOM_TYPE_LIST),
        ("parameterName", "RoomAvailRoomsYN"),
        ("parameterValue", "Y")
    ]

    response = requests.get(url, headers=headers, params=params)
    if response.status_code == 200:
        return response.json()
    else:
        return {
            "status": "error",
            "code": response.status_code,
            "message": response.text
        }
