# ==============================================
# ACDP API — FastAPI Implementation
# ==============================================
from fastapi import FastAPI, HTTPException, Query, Body
from fastapi.middleware.cors import CORSMiddleware
from datetime import datetime
from typing import Optional, List
from pymongo import MongoClient
from bson import ObjectId
import os

# ==============================================
# MongoDB Connection
# ==============================================
MONGO_URI = "mongodb://admin:admin123@mongodb:27017/mcp_adcp_db?authSource=admin"
client = MongoClient(MONGO_URI)
db = client["mcp_acdp_db"]

# ==============================================
# FastAPI Setup
# ==============================================
app = FastAPI(
    title="ACDP API",
    version="1.0.0",
    description="Advertising Context Data Protocol API built with FastAPI",
)

app.add_middleware(
    CORSMiddleware,
    allow_origins=["*"],
    allow_credentials=True,
    allow_methods=["*"],
    allow_headers=["*"],
)

# ==============================================
# Helper Functions
# ==============================================

def serialize_doc(doc):
    """Convert MongoDB documents to JSON-safe objects."""
    doc["_id"] = str(doc["_id"])
    return doc

# ==============================================
# ROUTES — CHANNELS
# ==============================================

@app.get("/api/v1/channels")
def get_channels():
    """List all channels."""
    channels = list(db['channels'].find())
    return [serialize_doc(c) for c in channels]

@app.get("/api/v1/adbreaks")
def get_adbreakd(available:Optional[bool]):
    """List all channels."""
    adbreaks = db['ad_breaks'].find({"is_sold":available})
    return [serialize_doc(c) for c in adbreaks]

@app.get("/api/v1/channels/{channel_id}")
def get_channel(channel_id: str):
    """Get single channel by ID."""
    channel = db.channels.find_one({"channel_id": channel_id})
    if not channel:
        raise HTTPException(status_code=404, detail="Channel not found")
    return serialize_doc(channel)

# ==============================================
# ROUTES — PROGRAMS (EPG)
# ==============================================

@app.get("/api/v1/programs")
def get_programs(channel: Optional[str] = None, date: Optional[str] = None):
    """Fetch EPG programs by channel and optional date."""
    query = {}
    if channel:
        query["channel_id"] = channel
    if date:
        try:
            start = datetime.fromisoformat(date)
            end = datetime.fromisoformat(date)  # same-day range
            end = end.replace(hour=23, minute=59, second=59)
            query["start_time"] = {"$gte": start, "$lte": end}
        except ValueError:
            raise HTTPException(status_code=400, detail="Invalid date format. Use YYYY-MM-DD")

    programs = list(db.programs.find(query))
    return [serialize_doc(p) for p in programs]

@app.get("/api/v1/programs/{program_id}")
def get_program(program_id: str):
    program = db.programs.find_one({"program_id": program_id})
    if not program:
        raise HTTPException(status_code=404, detail="Program not found")
    return serialize_doc(program)

# ==============================================
# ROUTES — INVENTORY (Ad Breaks + Prices)
# ==============================================

@app.get("/api/v1/inventory")
def get_inventory(
    channel: str = Query(..., description="Channel ID (e.g., al_aoula)"),
    date: str = Query(..., description="Date in YYYY-MM-DD"),
    region: Optional[str] = Query(None, description="Region (e.g., France)")
):
    """Return ad inventory by channel/date and optional region."""
    try:
        start = datetime.fromisoformat(date)
        end = start.replace(hour=23, minute=59, second=59)
    except ValueError:
        raise HTTPException(status_code=400, detail="Invalid date format. Use YYYY-MM-DD")

    # Find programs for that channel and day
    programs = list(db.programs.find({
        "channel_id": channel,
        "start_time": {"$gte": start, "$lte": end}
    }))
    program_ids = [p["program_id"] for p in programs]

    if not program_ids:
        return []

    ad_breaks = list(db.ad_breaks.find({"program_id": {"$in": program_ids}}))
    results = []

    for ad in ad_breaks:
        ad_data = serialize_doc(ad)
        price = db.inventory_prices.find_one({"inventory_id": ad["ad_break_id"]})
        if price:
            ad_data["price"] = serialize_doc(price)
        if region:
            audience = db.audience_data.find_one({
                "inventory_id": ad["ad_break_id"],
                "region": {"$regex": f"^{region}$", "$options": "i"}
            })
            if audience:
                ad_data["audience"] = serialize_doc(audience)
        results.append(ad_data)

    return results


@app.get("/api/v1/pricing")
def get_pricing(inventory_id: str = Query(..., description="Inventory/Ad Break ID")):
    """Get pricing info for a given ad break (inventory)."""
    price = db.inventory_prices.find_one({"inventory_id": inventory_id})
    if not price:
        raise HTTPException(status_code=404, detail="Pricing not found for this inventory ID")
    return serialize_doc(price)

# ==============================================
# ROUTES — BOOK AN AD (mark ad as sold)
# ==============================================

@app.post("/api/v1/book_ad")
def book_ad(inventory_id: str = Body(..., embed=True)):
    """Mark an ad break as sold."""
    ad_break = db.ad_breaks.find_one({"ad_break_id": inventory_id})
    if not ad_break:
        raise HTTPException(status_code=404, detail="Ad break not found")

    if ad_break.get("is_sold", False):
        raise HTTPException(status_code=400, detail="This ad is already sold")

    db.ad_breaks.update_one({"ad_break_id": inventory_id}, {"$set": {"is_sold": True}})
    return {"message": "Ad booked successfully", "inventory_id": inventory_id}

# ==============================================
# ROUTES — AUDIENCE DATA
# ==============================================

@app.get("/api/v1/audience")
def get_audience(inventory_id: Optional[str] = None, region: Optional[str] = None):
    """Fetch audience data by inventory or region."""
    query = {}
    if inventory_id:
        query["inventory_id"] = inventory_id
    if region:
        query["region"] = {"$regex": f"^{region}$", "$options": "i"}

    data = list(db.audience_data.find(query))
    return [serialize_doc(d) for d in data]

# ==============================================
# ROOT ENDPOINT
# ==============================================

@app.get("/")
def root():
    return {
        "status": "ok",
        "api": "ACDP v1",
        "message": "Advertising Context Data Protocol API is running 🚀"
    }
