import logging
from typing import Optional
from fastapi import APIRouter, Depends, HTTPException, status, BackgroundTasks
from pydantic import BaseModel
from sqlalchemy.orm import Session

import httpx

from config import settings
from database import get_db
from models.order import Order
from schemas.order import OrderOut
from routers.deps import get_current_user, require_manager
from models.user import User
from services.sse_bus import broadcast_sync

logger = logging.getLogger(__name__)
router = APIRouter()


class RejectRequest(BaseModel):
    reason: Optional[str] = None


class StatusUpdateRequest(BaseModel):
    status: str  # "preparing" | "ready" | "out_for_delivery" | "delivered"


# ── Helpers ───────────────────────────────────────────────────────────────────

def _get_online_order(order_id: int, db: Session) -> Order:
    order = db.query(Order).filter(Order.id == order_id, Order.source == "online").first()
    if not order:
        raise HTTPException(status_code=404, detail="Online order not found")
    return order


def _cloud_headers() -> dict:
    return {"X-Site-ID": settings.SITE_ID, "X-Site-Key": settings.SITE_KEY}


async def _mirror_status_to_cloud(cloud_order_id: int, new_status: str, rejection_reason: str = None):
    """Best-effort push of status update to cloud. Failures are logged, not raised."""
    if not settings.CLOUD_URL or not cloud_order_id:
        return
    try:
        body = {"status": new_status}
        if rejection_reason:
            body["rejection_reason"] = rejection_reason

        async with httpx.AsyncClient(timeout=10) as client:
            resp = await client.patch(
                f"{settings.CLOUD_URL}/api/orders/{cloud_order_id}/status",
                headers=_cloud_headers(),
                json=body,
            )
            resp.raise_for_status()
        logger.info("Mirrored status %s for cloud order id %d", new_status, cloud_order_id)

    except Exception as e:
        logger.warning("Failed to mirror status to cloud for order id %d: %s", cloud_order_id, e)


# ── Endpoints ─────────────────────────────────────────────────────────────────

@router.get("/orders", response_model=list[OrderOut])
def get_orders_by_status(
    status: str,
    db: Session = Depends(get_db),
    user: User = Depends(get_current_user),
):
    """
    ?status=active  → accepted | preparing | ready | out_for_delivery, newest first
    ?status=history → delivered | rejected, newest first, limit 50
    """
    if status == "active":
        statuses = ["accepted", "preparing", "ready", "out_for_delivery"]
        orders = (
            db.query(Order)
            .filter(Order.source == "online", Order.online_status.in_(statuses))
            .order_by(Order.opened_at.desc())
            .all()
        )
    elif status == "history":
        statuses = ["delivered", "rejected"]
        orders = (
            db.query(Order)
            .filter(Order.source == "online", Order.online_status.in_(statuses))
            .order_by(Order.opened_at.desc())
            .limit(50)
            .all()
        )
    else:
        raise HTTPException(status_code=400, detail=f"Unknown status filter '{status}'. Use 'active' or 'history'.")
    return orders


@router.get("/orders/incoming", response_model=list[OrderOut])
def get_incoming_orders(
    db: Session = Depends(get_db),
    user: User = Depends(get_current_user),
):
    """Return all online orders pending acceptance, newest first."""
    orders = (
        db.query(Order)
        .filter(Order.source == "online", Order.online_status == "pending_acceptance")
        .order_by(Order.opened_at.desc())
        .all()
    )
    return orders


@router.post("/orders/{order_id}/accept", response_model=OrderOut)
async def accept_order(
    order_id: int,
    background: BackgroundTasks,
    db: Session = Depends(get_db),
    user: User = Depends(require_manager),
):
    order = _get_online_order(order_id, db)
    if order.online_status != "pending_acceptance":
        raise HTTPException(status_code=400, detail=f"Order is already '{order.online_status}'")

    order.online_status = "accepted"
    db.commit()
    db.refresh(order)

    background.add_task(_mirror_status_to_cloud, order.online_order_cloud_id, "accepted")
    broadcast_sync("online_order_updated", {"order_id": order_id, "status": "accepted"})
    return order


@router.post("/orders/{order_id}/reject", response_model=OrderOut)
async def reject_order(
    order_id: int,
    body: RejectRequest,
    background: BackgroundTasks,
    db: Session = Depends(get_db),
    user: User = Depends(require_manager),
):
    order = _get_online_order(order_id, db)
    if order.online_status != "pending_acceptance":
        raise HTTPException(status_code=400, detail=f"Order is already '{order.online_status}'")

    order.online_status = "rejected"
    order.status = "cancelled"
    db.commit()
    db.refresh(order)

    background.add_task(_mirror_status_to_cloud, order.online_order_cloud_id, "rejected", body.reason)
    broadcast_sync("online_order_updated", {"order_id": order_id, "status": "rejected"})
    return order


@router.post("/orders/{order_id}/status", response_model=OrderOut)
async def update_order_status(
    order_id: int,
    body: StatusUpdateRequest,
    background: BackgroundTasks,
    db: Session = Depends(get_db),
    user: User = Depends(require_manager),
):
    allowed = {"preparing", "ready", "out_for_delivery", "delivered"}
    if body.status not in allowed:
        raise HTTPException(status_code=400, detail=f"Invalid status '{body.status}'")

    order = _get_online_order(order_id, db)
    order.online_status = body.status
    if body.status == "delivered":
        order.status = "closed"
    db.commit()
    db.refresh(order)

    background.add_task(_mirror_status_to_cloud, order.online_order_cloud_id, body.status)
    broadcast_sync("online_order_updated", {"order_id": order_id, "status": body.status})
    return order
