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

from bson import ObjectId
from fastapi import APIRouter, Depends, File, Form, HTTPException, Path, Query, UploadFile, status
from fastapi.security import HTTPAuthorizationCredentials, HTTPBearer
from pydantic import BaseModel, Field, validator

from app.db.db import get_col
# from app.models.blogs import  BlogCreate, BlogUpdate
from app.utility.cloudinary_utils import (
    delete_image_from_cloudinary,
    extract_public_id_from_url,
    upload_image_to_cloudinary,
)
from app.utility.security import verify_jwt

router = APIRouter(prefix="/blogs", tags=["blogs"])
auth_scheme = HTTPBearer(auto_error=False)

def _ensure_object_id(id_str: str) -> ObjectId:
    try:
        return ObjectId(id_str)
    except Exception as exc:
        raise HTTPException(status_code=status.HTTP_400_BAD_REQUEST, detail="Invalid identifier") from exc


def _require_admin(credentials: HTTPAuthorizationCredentials = Depends(auth_scheme)) -> Dict[str, Any]:
    if not credentials:
        raise HTTPException(status_code=status.HTTP_401_UNAUTHORIZED, detail="Not authenticated")
    ok, payload = verify_jwt(credentials.credentials)
    if not ok or not payload:
        raise HTTPException(status_code=status.HTTP_401_UNAUTHORIZED, detail="Invalid token")
    if payload.get("role") != "admin":
        raise HTTPException(status_code=status.HTTP_403_FORBIDDEN, detail="Admin access required")
    admins = get_col("admins")
    admin = admins.find_one({"_id": _ensure_object_id(payload["sub"])})
    if not admin:
        raise HTTPException(status_code=status.HTTP_401_UNAUTHORIZED, detail="Admin not found")
    return admin


def _serialize_datetime(value: Any) -> Any:
    if isinstance(value, datetime):
        return value.isoformat()
    return value

def _serialize_blog(doc: Dict[str, Any]) -> Dict[str, Any]:
    """Convert MongoDB document to JSON-serializable dict, converting ObjectId to string."""
    return {
        "id": str(doc["_id"]),
        "title": doc.get("title"),
        "content": doc.get("content"),
        "image": doc.get("image", []),
        "blog_url": doc.get("blog_url"),
        "blog_meta_title": doc.get("blog_meta_title"),
        "blog_meta_description": doc.get("blog_meta_description"),
        "blog_meta_keywords": doc.get("blog_meta_keywords"),
        "blog_schema_markup": doc.get("blog_schema_markup"),
        "createdAt": _serialize_datetime(doc.get("createdAt")),
        "updatedAt": _serialize_datetime(doc.get("updatedAt")),
    }

@router.post("/create/blogs", status_code=status.HTTP_201_CREATED)
def create_blog(
    title: str = Form(..., min_length=3, max_length=100),
    content: str = Form(..., min_length=10, max_length=1000),
    images: List[UploadFile] = File(...),
    blog_url: str = Form(..., min_length=10, max_length=100),
    blog_meta_title: Optional[str] = Form(None, min_length=3, max_length=100),
    blog_meta_description: Optional[str] = Form(None, min_length=10, max_length=1000),
    blog_meta_keywords: Optional[List[str]] = Form(None),
    blog_schema_markup: Optional[str] = Form(None, min_length=10, max_length=1000),
    _admin=Depends(_require_admin),
):
    blogs = get_col("blogs")

    image_urls = []
    for image in images:
        image_urls.append(upload_image_to_cloudinary(image))

    blog_data = {
        "title": title,
        "content": content,
        "image": image_urls,
        "blog_url": blog_url,
        "blog_meta_title": blog_meta_title,
        "blog_meta_description": blog_meta_description,
        "blog_meta_keywords": blog_meta_keywords,
        "blog_schema_markup": blog_schema_markup,
        "createdAt": datetime.utcnow(),
        "updatedAt": datetime.utcnow(),
    }

    result = blogs.insert_one(blog_data)
    # Fetch the inserted document to get the _id
    inserted_doc = blogs.find_one({"_id": result.inserted_id})
    return _serialize_blog(inserted_doc)

@router.get("/all/blogs", status_code=status.HTTP_200_OK)   
def get_blogs():
    blogs = get_col("blogs")
    docs = list(blogs.find())
    return [_serialize_blog(doc) for doc in docs]

@router.get("/blog/{blog_url}", status_code=status.HTTP_200_OK)
def get_blog(blog_url: str):
    blogs = get_col("blogs")
    doc = blogs.find_one({"blog_url": blog_url})
    if not doc:
        raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail="Blog not found")
    return _serialize_blog(doc)

@router.put("/update/blog/{blog_id}", status_code=status.HTTP_200_OK)
def update_blog(
    blog_id: str,
    title: Optional[str] = Form(None, min_length=3, max_length=100),
    content: Optional[str] = Form(None, min_length=10, max_length=1000),
    images: Optional[List[UploadFile]] = File(None),
    blog_url: Optional[str] = Form(None, min_length=10, max_length=100),
    blog_meta_title: Optional[str] = Form(None, min_length=3, max_length=100),
    blog_meta_description: Optional[str] = Form(None, min_length=10, max_length=1000),
    blog_meta_keywords: Optional[List[str]] = Form(None),
    blog_schema_markup: Optional[str] = Form(None, min_length=10, max_length=1000),
    _admin=Depends(_require_admin),
):
    blogs = get_col("blogs")
    doc = blogs.find_one({"_id": ObjectId(blog_id)})

    if not doc:
        raise HTTPException(status_code=404, detail="Blog not found")

    update_data = {}

    # 🟦 Basic fields
    if title is not None:
        update_data["title"] = title
    if content is not None:
        update_data["content"] = content
    if blog_url is not None:
        update_data["blog_url"] = blog_url
    if blog_meta_title is not None:
        update_data["blog_meta_title"] = blog_meta_title
    if blog_meta_description is not None:
        update_data["blog_meta_description"] = blog_meta_description
    if blog_meta_keywords is not None:
        update_data["blog_meta_keywords"] = blog_meta_keywords
    if blog_schema_markup is not None:
        update_data["blog_schema_markup"] = blog_schema_markup

    # 🟩 IMAGE HANDLING
    if images is not None:
        # If frontend sends empty list → delete all images
        if len(images) == 0:
            for img_url in doc.get("image", []):
                public_id = extract_public_id_from_url(img_url)
                delete_image_from_cloudinary(public_id)
            update_data["image"] = []

        # If new images uploaded → replace old
        else:
            # delete old images
            for img_url in doc.get("image", []):
                public_id = extract_public_id_from_url(img_url)
                delete_image_from_cloudinary(public_id)

            # upload new images
            new_urls = []
            for file in images:
                new_urls.append(upload_image_to_cloudinary(file))

            update_data["image"] = new_urls

    # Timestamp
    update_data["updatedAt"] = datetime.utcnow()

    # Save changes
    blogs.update_one({"_id": doc["_id"]}, {"$set": update_data})

    updated_doc = blogs.find_one({"_id": doc["_id"]})
    return _serialize_blog(updated_doc)


@router.delete("/delete/blog/{blog_id}", status_code=status.HTTP_200_OK)
def delete_blog(blog_id: str, _admin=Depends(_require_admin)):
    blogs = get_col("blogs")
    doc = blogs.find_one({"_id": ObjectId(blog_id)})
    if not doc:
        raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail="Blog not found")
    blogs.delete_one({"_id": doc["_id"]})
    return {"message": "Blog deleted successfully"}

