from fastapi import APIRouter, HTTPException, Depends, Request
from pydantic import BaseModel, Field
from typing import List, Optional
import traceback
from utils.auth_helper import requires_permission, assert_actor_match
from utils.turnstile_helper import verify_turnstile

from model.order_model import OrderModel

router = APIRouter()


class AddressPayload(BaseModel):
    street: Optional[str] = None
    city: Optional[str] = None
    state: Optional[str] = None
    country: Optional[str] = None
    zipCode: Optional[str] = None


class CustomerPayload(BaseModel):
    name: Optional[str] = None
    phone: Optional[str] = None
    email: Optional[str] = None
    address: Optional[AddressPayload] = None


class OrderItemPayload(BaseModel):
    style: str
    quantity: int
    price: float
    color: str
    size: str
    design: str
    shipping: float
    tax: float


class UpdateOrderRequest(BaseModel):
    customer: Optional[CustomerPayload] = None
    items: Optional[List[OrderItemPayload]] = None


class PayOrdersRequest(BaseModel):
    orderIds: List[str] = Field(default_factory=list)
    id_khach_hang: str


class AdminUpdateOrderStatusRequest(BaseModel):
    status: str
    trackingNumber: Optional[str] = None
    trackingLink: Optional[str] = None
    actorId: str


class AdminBulkUpdateOrderStatusRequest(BaseModel):
    docIds: List[str] = Field(default_factory=list)
    status: str
    trackingNumber: Optional[str] = None
    trackingLink: Optional[str] = None
    actorId: str


@router.get("/")
async def get_all_orders(
    id_khach_hang: str,
    keyword: Optional[str] = None,
    status: Optional[str] = "All",
    dateFrom: Optional[str] = None,
    dateTo: Optional[str] = None,
    page: int = 1,
    pageSize: int = 5,
):
    try:
        result = OrderModel.get_all_orders(
            id_khach_hang=id_khach_hang,
            keyword=keyword,
            status=status,
            dateFrom=dateFrom,
            dateTo=dateTo,
            page=page,
            page_size=pageSize,
        )
        return {"success": True, **result}
    except ValueError as e:
        raise HTTPException(status_code=400, detail=str(e))
    except Exception:
        raise HTTPException(status_code=500, detail="Failed to fetch orders")


@router.get("/admin/search", dependencies=[Depends(requires_permission("order_search"))])
async def admin_get_all_orders(
    keyword: Optional[str] = None,
    status: Optional[str] = "All",
    dateFrom: Optional[str] = None,
    dateTo: Optional[str] = None,
    page: int = 1,
    pageSize: int = 10,
):
    try:
        result = OrderModel.admin_get_all_orders(
            keyword=keyword,
            status=status,
            dateFrom=dateFrom,
            dateTo=dateTo,
            page=page,
            page_size=pageSize,
        )
        return {"success": True, **result}
    except ValueError as e:
        raise HTTPException(status_code=400, detail=str(e))
    except Exception:
        raise HTTPException(status_code=500, detail="Failed to fetch admin orders")
    
@router.get("/admin/dashboard-summary", dependencies=[Depends(requires_permission("view_dashboard"))])
async def admin_get_dashboard_summary(
    dateFrom: Optional[str] = None,
    dateTo: Optional[str] = None,
    salesPage: int = 1,
    salesPageSize: int = 15,
    salesSortBy: str = "revenue",
    salesSortOrder: str = "desc",
):
    try:
        data = OrderModel.admin_get_dashboard_summary(
            dateFrom=dateFrom,
            dateTo=dateTo,
            salesPage=salesPage,
            salesPageSize=salesPageSize,
            salesSortBy=salesSortBy,
            salesSortOrder=salesSortOrder,
        )
        return {"success": True, "data": data}
    except ValueError as e:
        raise HTTPException(status_code=400, detail=str(e))
    except Exception:
        raise HTTPException(status_code=500, detail="Failed to fetch dashboard summary")

@router.put("/admin/batch-status", dependencies=[Depends(verify_turnstile)])
async def admin_batch_update_order_status(
    req: AdminBulkUpdateOrderStatusRequest,
    current_user=Depends(requires_permission("order_operations"))
):
    try:
        actor_id = current_user["id"]
        actor_name = current_user.get("name", "")
        assert_actor_match(current_user, req.actorId)

        data = OrderModel.admin_batch_update_order_status(
            doc_ids=req.docIds,
            new_status=req.status,
            tracking_number=req.trackingNumber,
            tracking_link=req.trackingLink,
        )

        return {
            "success": True,
            "data": data,
            "message": f"Updated {data['updatedCount']} orders to {req.status}",
            "actedBy": {
                "id": actor_id,
                "name": actor_name
            }
        }
    except ValueError as e:
        raise HTTPException(status_code=400, detail=str(e))
    except Exception as e:
        traceback.print_exc()
        raise HTTPException(status_code=500, detail=f"Failed to update admin batch order status: {str(e)}")


@router.put("/admin/{identifier}/status", dependencies=[Depends(verify_turnstile)])
async def admin_update_order_status(
    identifier: str,
    req: AdminUpdateOrderStatusRequest,
    current_user=Depends(requires_permission("order_operations"))
):
    try:
        actor_id = current_user["id"]
        actor_name = current_user.get("name", "")
        assert_actor_match(current_user, req.actorId)

        data = OrderModel.admin_update_order_status(
            identifier=identifier,
            new_status=req.status,
            tracking_number=req.trackingNumber,
            tracking_link=req.trackingLink,
        )

        return {
            "success": True,
            "data": data,
            "message": f"Order {identifier} updated to {req.status}",
            "actedBy": {
                "id": actor_id,
                "name": actor_name
            }
        }
    except ValueError as e:
        raise HTTPException(status_code=400, detail=str(e))
    except Exception as e:
        traceback.print_exc()
        raise HTTPException(status_code=500, detail=f"Failed to update admin order status: {str(e)}")


@router.post("/admin/{identifier}/cancel", dependencies=[Depends(verify_turnstile)])
async def admin_cancel_order(
    identifier: str,
    request: Request,
    current_user=Depends(requires_permission("order_operations"))
):
    try:
        actor_id = current_user["id"]
        actor_name = current_user.get("name", "")
        assert_actor_match(current_user, request.headers.get("x-actor-id"))

        result = OrderModel.admin_cancel_order(
            identifier=identifier,
            admin_id=actor_id,
            admin_name=actor_name,
        )

        return {
            "success": True,
            "data": result["order"],
            "refundAmount": result["refundAmount"],
            "refundTxId": result["refundTxId"],
            "message": f"Order {identifier} was cancelled and refunded successfully",
            "actedBy": {
                "id": actor_id,
                "name": actor_name
            }
        }
    except ValueError as e:
        raise HTTPException(status_code=400, detail=str(e))
    except Exception as e:
        traceback.print_exc()
        raise HTTPException(status_code=500, detail=f"Failed to cancel admin order: {str(e)}")


@router.get("/admin/{identifier}", dependencies=[Depends(requires_permission("order_search"))])
async def admin_get_order_detail(identifier: str):
    try:
        data = OrderModel.admin_get_order_detail(identifier)
        return {"success": True, "data": data}
    except ValueError as e:
        raise HTTPException(status_code=404, detail=str(e))
    except Exception as e:
        traceback.print_exc()
        raise HTTPException(status_code=500, detail=f"Failed to fetch admin order detail: {str(e)}")


@router.get("/{order_id}")
async def get_order_detail(order_id: str, id_khach_hang: str):
    try:
        data = OrderModel.get_order_detail(order_id, id_khach_hang)
        return {"success": True, "data": data}
    except ValueError as e:
        raise HTTPException(status_code=404, detail=str(e))
    except Exception as e:
        traceback.print_exc()
        raise HTTPException(status_code=500, detail=f"Failed to fetch order detail: {str(e)}")


@router.put("/{order_id}", dependencies=[Depends(verify_turnstile)])
async def update_order(order_id: str, id_khach_hang: str, req: UpdateOrderRequest):
    try:
        update_data = req.dict(exclude_unset=True, exclude_none=True)
        data = OrderModel.update_order(order_id, id_khach_hang, update_data)
        return {
            "success": True,
            "data": data,
            "message": "Order updated successfully",
        }
    except ValueError as e:
        raise HTTPException(status_code=400, detail=str(e))
    except Exception:
        raise HTTPException(status_code=500, detail="Failed to update order")


@router.post("/{order_id}/cancel", dependencies=[Depends(verify_turnstile)])
async def cancel_order(order_id: str, id_khach_hang: str):
    try:
        OrderModel.cancel_order(order_id, id_khach_hang)
        return {
            "success": True,
            "message": f"Order {order_id} has been cancelled",
        }
    except ValueError as e:
        raise HTTPException(status_code=400, detail=str(e))
    except Exception:
        raise HTTPException(status_code=500, detail="Failed to cancel order")


@router.post("/pay", dependencies=[Depends(verify_turnstile)])
async def pay_orders(req: PayOrdersRequest):
    try:
        if not req.orderIds:
            raise ValueError("No orders selected for payment")

        result = OrderModel.pay_orders(req.orderIds, req.id_khach_hang)

        return {
            "success": True,
            "paidCount": result["paidCount"],
            "totalAmount": result["totalAmount"],
            "message": f"Successfully paid {result['paidCount']} orders totaling ${result['totalAmount']:.2f}",
        }
    except ValueError as e:
        raise HTTPException(status_code=400, detail=str(e))
    except Exception:
        raise HTTPException(status_code=500, detail="Failed to pay orders")