from datetime import datetime
from typing import List, Dict, Any

from bson import ObjectId
from fastapi import APIRouter, Depends, HTTPException, Path, status
from fastapi.security import HTTPAuthorizationCredentials, HTTPBearer

from app.utility.security import verify_jwt
from app.db.db import get_col
from app.models.ShippFee import ShippingFee, ShippingFeeResponse

router = APIRouter(prefix="/shipping-fees", tags=["Shipping Fees"])

shipping_fee_col = get_col("shipping_fees")

# FIX: Define the missing auth scheme
auth_scheme = HTTPBearer()


def _require_admin(credentials: HTTPAuthorizationCredentials = Depends(auth_scheme)) -> Dict[str, Any]:
    if not credentials:
        raise HTTPException(status_code=401, detail="Not authenticated")

    token = credentials.credentials

    # Your verify_jwt returns -> (ok, payload)
    ok, payload = verify_jwt(token)

    if not ok or not payload:
        raise HTTPException(status_code=401, detail="Invalid or expired token")

    if payload.get("role") != "admin":
        raise HTTPException(status_code=403, detail="Admin access required")

    # Optional admin validation in DB
    admins = get_col("admins")
    admin = admins.find_one({"_id": _ensure_object_id(payload["sub"])})

    if not admin:
        raise HTTPException(status_code=401, detail="Admin not found")

    return admin


def _ensure_object_id(identifier: str) -> ObjectId:
    if not ObjectId.is_valid(identifier):
        raise HTTPException(status_code=400, detail="Invalid identifier")
    return ObjectId(identifier)


def _serialize_fee(doc) -> ShippingFeeResponse:
    return ShippingFeeResponse(
        id=str(doc["_id"]),
        state=doc["state"],
        combo_fee=doc["combo_fee"],
        delivery_fee=doc["delivery_fee"],
        above_500_fee=doc["above_500_fee"],
        createdAt=doc.get("createdAt", datetime.utcnow()),
        updatedAt=doc.get("updatedAt", datetime.utcnow()),
    )



@router.post("/admin/create", status_code=201)
def create_shipping_fee(payload: ShippingFee, admin=Depends(_require_admin)):
    now = datetime.utcnow()
    body = payload.dict()
    body["createdAt"] = now
    body["updatedAt"] = now

    res = shipping_fee_col.insert_one(body)
    created = shipping_fee_col.find_one({"_id": res.inserted_id})
    return {"message": "Shipping fee created", "data": _serialize_fee(created)}


@router.get("/admin/get-all", response_model=List[ShippingFeeResponse])
def list_shipping_fees_admin(admin=Depends(_require_admin)):
    return [_serialize_fee(doc) for doc in shipping_fee_col.find()]



@router.get("/admin/{fee_id}", response_model=ShippingFeeResponse)
def get_shipping_fee_admin(fee_id: str, admin=Depends(_require_admin)):
    fee = shipping_fee_col.find_one({"_id": _ensure_object_id(fee_id)})
    if not fee:
        raise HTTPException(status_code=404, detail="Shipping fee not found")
    return _serialize_fee(fee)


@router.put("/admin/update/{fee_id}", status_code=200)
def update_shipping_fee(fee_id: str, payload: ShippingFee, admin=Depends(_require_admin)):
    fee_oid = _ensure_object_id(fee_id)
    body = payload.dict()
    body["updatedAt"] = datetime.utcnow()

    res = shipping_fee_col.update_one({"_id": fee_oid}, {"$set": body})
    if res.matched_count == 0:
        raise HTTPException(status_code=404, detail="Shipping fee not found")

    fee = shipping_fee_col.find_one({"_id": fee_oid})
    return {"message": "Shipping fee updated", "data": _serialize_fee(fee)}


@router.delete("/admin/delete/{fee_id}", status_code=200)
def delete_shipping_fee(fee_id: str, admin=Depends(_require_admin)):
    res = shipping_fee_col.delete_one({"_id": _ensure_object_id(fee_id)})
    if res.deleted_count == 0:
        raise HTTPException(status_code=404, detail="Shipping fee not found")

    return {"message": "Shipping fee deleted"}


@router.get("/all-fees", response_model=List[ShippingFeeResponse])
def get_all_shipping_fees():
    return [_serialize_fee(doc) for doc in shipping_fee_col.find()]
