from fastapi import APIRouter, HTTPException, Request, Depends
from model.product import ProductDatabaseModel
from MongoDBConnection import MONGO_URI, DB_NAME, categories_collection
from utils.auth_helper import requires_permission
from utils.turnstile_helper import verify_turnstile

router = APIRouter()

db_model = ProductDatabaseModel(
    db_uri=MONGO_URI,
    db_name=DB_NAME,
    collection_name="products"
)


def _public_root_url(request: Request) -> str:
    """
    request.base_url có thể là:
    - https://05factory.com/pod-api/
    - https://05factory.com/pod-api/api/

    Static file đang public dưới /pod-api/uploads,
    nên nếu base_url kết thúc bằng /api thì bỏ /api đi.
    """
    root = str(request.base_url).rstrip("/")

    if root.endswith("/api"):
        root = root[:-4]

    return root


def _format_upload_url(request: Request, value: str) -> str:
    raw = str(value or "").strip()
    if not raw:
        return ""

    if raw.startswith("http"):
        return raw

    raw = raw.replace("\\", "/").strip()

    # Nếu DB đã lưu sẵn public path thì giữ lại dạng path browser dùng được.
    if raw.startswith("/pod-api/uploads/") or raw.startswith("/uploads/"):
        return raw

    raw = raw.lstrip("/")

    if raw.startswith("pod-api/uploads/"):
        return f"/{raw}"

    if raw.startswith("uploads/"):
        return f"{_public_root_url(request)}/{raw}"

    if raw.startswith("upload_img/"):
        return f"{_public_root_url(request)}/uploads/{raw}"

    # Chuẩn hiện tại: DB chỉ lưu tên file.
    return f"{_public_root_url(request)}/uploads/upload_img/{raw}"


def _unique_values(values: list[str]) -> list[str]:
    result = []
    seen = set()

    for value in values:
        cleaned = str(value or "").strip()
        if not cleaned:
            continue

        key = cleaned.lower()
        if key in seen:
            continue

        seen.add(key)
        result.append(cleaned)

    return result


def _resolve_category_names(category_id: str) -> list[str]:
    """
    Frontend có thể gửi:
    - slug/_id: craft-handmade
    - name: Craft / Handmade

    Product trong DB hiện lưu:
    - categoryName: Craft / Handmade

    Vì vậy cần resolve slug/_id về name trước khi query products.
    """
    raw = str(category_id or "").strip()
    if not raw:
        return []

    candidates = [raw]

    category_doc = categories_collection.find_one({
        "$or": [
            {"_id": raw},
            {"slug": raw},
            {"name": raw},
        ]
    })

    if category_doc:
        candidates.extend([
            category_doc.get("name", ""),
            category_doc.get("slug", ""),
            category_doc.get("_id", ""),
        ])

    return _unique_values(candidates)


def _normalize_update_payload(update_data: dict) -> dict:
    normalized = dict(update_data)

    new_product_id = str(normalized.pop("id", "") or "").strip()
    if new_product_id:
        normalized["productId"] = new_product_id

    normalized["description"] = normalized.get("description", "") or ""
    normalized["additionalNote"] = normalized.get("additionalNote", "") or ""
    normalized["materials"] = normalized.get("materials", []) or []
    normalized["styles"] = normalized.get("styles", []) or []
    normalized["variants"] = normalized.get("variants", []) or []
    normalized["shippingRates"] = normalized.get("shippingRates", []) or []
    normalized["sizeGuide"] = normalized.get("sizeGuide", []) or []

    return normalized


@router.get("/products")
async def get_public_products(request: Request, categoryId: str = None):
    try:
        query = {}

        if categoryId:
            category_names = _resolve_category_names(categoryId)

            if category_names:
                query["categoryName"] = {"$in": category_names}
            else:
                query["categoryName"] = categoryId

        products_cursor = db_model.collection.find(query)

        result_list = []
        for p in products_cursor:
            images = p.get("images", []) or []
            img_name = images[0] if len(images) > 0 else ""
            image_url = _format_upload_url(request, img_name) if img_name else ""

            raw_materials = p.get("materials", []) or []
            formatted_materials = []
            for material in raw_materials:
                formatted_materials.append({
                    "name": material.get("name", ""),
                    "thumbnail": _format_upload_url(request, material.get("thumbnail", ""))
                })

            item = {
                "id": p.get("productId", ""),
                "title": p.get("title", ""),
                "categoryId": p.get("categoryName", "").lower(),
                "categoryName": p.get("categoryName", ""),
                "subCategory": p.get("subCategory", ""),
                "price": float(p.get("price", 0)),
                "badge": p.get("badge", ""),
                "badgeColor": p.get("badgeColor", "#3b82f6"),
                "image": image_url,
                "materials": formatted_materials
            }

            result_list.append(item)

        return {
            "error": False,
            "data": result_list
        }
    except Exception as e:
        return {"error": True, "message": str(e)}


@router.get("/products/{product_id}")
async def get_product_detail(request: Request, product_id: str):
    try:
        p = db_model.collection.find_one({"productId": product_id})

        if not p:
            raise HTTPException(status_code=404, detail="Product not found")

        raw_images = p.get("images", []) or []
        formatted_images = []
        for img in raw_images:
            formatted_images.append(_format_upload_url(request, img) if img else "")

        formatted_images = [img for img in formatted_images if img]

        if not formatted_images:
            formatted_images = ["https://via.placeholder.com/500"]

        raw_styles = p.get("styles", []) or []
        formatted_styles = []
        for style in raw_styles:
            formatted_styles.append({
                "name": style.get("name", ""),
                "thumbnail": _format_upload_url(request, style.get("thumbnail", ""))
            })

        raw_materials = p.get("materials", []) or []
        formatted_materials = []
        for material in raw_materials:
            formatted_materials.append({
                "name": material.get("name", ""),
                "thumbnail": _format_upload_url(request, material.get("thumbnail", ""))
            })

        item = {
            "id": p.get("productId", ""),
            "title": p.get("title", ""),
            "categoryId": p.get("categoryName", "").lower(),
            "categoryName": p.get("categoryName", ""),
            "subCategory": p.get("subCategory", ""),
            "price": float(p.get("price", 0)),
            "description": p.get("description", ""),
            "additionalNote": p.get("additionalNote", ""),
            "badge": p.get("badge", ""),
            "badgeColor": p.get("badgeColor", "#3b82f6"),
            "images": formatted_images,
            "sizes": p.get("sizes", []),
            "materials": formatted_materials,
            "styles": formatted_styles,
            "designTemplate": p.get("designTemplate", {
                "width": 4500,
                "height": 5400,
                "dpi": 300
            }),
            "variants": p.get("variants", []) or [],
            "shippingRates": p.get("shippingRates", []) or [],
            "sizeGuide": p.get("sizeGuide", []) or []
        }

        return {
            "error": False,
            "data": item
        }
    except HTTPException as he:
        raise he
    except Exception as e:
        return {"error": True, "message": str(e)}


@router.put(
    "/products/{product_id}",
    dependencies=[Depends(verify_turnstile), Depends(requires_permission("product_management"))]
)
async def update_product(product_id: str, request: Request):
    try:
        update_data = await request.json()

        existing_product = db_model.collection.find_one({"productId": product_id})
        if not existing_product:
            raise HTTPException(status_code=404, detail="Không tìm thấy sản phẩm để cập nhật")

        normalized_update_data = _normalize_update_payload(update_data)

        new_product_id = str(normalized_update_data.get("productId") or "").strip()

        if new_product_id and new_product_id != product_id:
            duplicated = db_model.collection.find_one({"productId": new_product_id})
            if duplicated:
                raise HTTPException(
                    status_code=400,
                    detail="Product ID đã tồn tại, vui lòng chọn ID khác"
                )

        result = db_model.collection.update_one(
            {"productId": product_id},
            {"$set": normalized_update_data}
        )

        if result.modified_count == 0:
            return {"success": True, "message": "Dữ liệu không có thay đổi so với bản cũ"}

        return {
            "success": True,
            "message": "Cập nhật sản phẩm thành công!"
        }
    except HTTPException as he:
        raise he
    except Exception as e:
        return {"success": False, "message": f"Lỗi hệ thống: {str(e)}"}


@router.delete(
    "/products/{product_id}",
    dependencies=[Depends(verify_turnstile), Depends(requires_permission("product_management"))]
)
async def delete_product(product_id: str):
    try:
        result = db_model.collection.delete_one({"productId": product_id})

        if result.deleted_count == 0:
            raise HTTPException(status_code=404, detail="Sản phẩm không tồn tại hoặc đã bị xóa trước đó")

        return {
            "success": True,
            "message": f"Đã xóa vĩnh viễn sản phẩm {product_id}!"
        }
    except HTTPException as he:
        raise he
    except Exception as e:
        return {"success": False, "message": f"Lỗi khi xóa: {str(e)}"}