import os
from datetime import datetime, timezone
from typing import Optional

from bson import ObjectId
from pydantic import BaseModel, Field

from MongoDBConnection import blogs_collection


BLOG_THUMBNAIL_PREFIX = "/pod-api/uploads/upload_img"


class BlogPayload(BaseModel):
    title: str = Field(..., min_length=1)
    description: str = Field(..., min_length=1)
    thumbnail: str = Field(..., min_length=1)


class BlogModel:
    @staticmethod
    def _now_iso() -> str:
        return datetime.now(timezone.utc).strftime("%Y-%m-%dT%H:%M:%S.000Z")

    @staticmethod
    def _clean_thumbnail(value: str) -> str:
        """
        FE có thể gửi:
        - photo-xxx.jpg
        - /pod-api/uploads/upload_img/photo-xxx.jpg
        - https://domain.com/pod-api/uploads/upload_img/photo-xxx.jpg

        DB chỉ lưu:
        - photo-xxx.jpg
        """
        raw = str(value or "").strip()
        if not raw:
            return ""

        raw = raw.split("?")[0].strip()
        raw = raw.replace("\\", "/")

        if "/upload_img/" in raw:
            raw = raw.split("/upload_img/")[-1]

        return os.path.basename(raw)

    @staticmethod
    def _thumbnail_url(filename: str) -> str:
        filename = str(filename or "").strip()
        if not filename:
            return ""
        return f"{BLOG_THUMBNAIL_PREFIX}/{filename}"

    @classmethod
    def _serialize_blog(cls, doc: dict) -> dict:
        if not doc:
            return {}

        thumbnail = str(doc.get("thumbnail") or "").strip()

        return {
            "id": str(doc.get("_id")),
            "title": doc.get("title", ""),
            "description": doc.get("description", ""),
            "thumbnail": thumbnail,
            "thumbnailUrl": cls._thumbnail_url(thumbnail),
            "createdAt": doc.get("createdAt", ""),
            "updatedAt": doc.get("updatedAt", ""),
        }

    @classmethod
    def create_blog(cls, payload: BlogPayload) -> dict:
        title = str(payload.title or "").strip()
        description = str(payload.description or "").strip()
        thumbnail = cls._clean_thumbnail(payload.thumbnail)

        if not title:
            raise ValueError("Title is required")

        if not description:
            raise ValueError("Description is required")

        if not thumbnail:
            raise ValueError("Thumbnail is required")

        now = cls._now_iso()

        doc = {
            "title": title,
            "description": description,
            "thumbnail": thumbnail,
            "createdAt": now,
            "updatedAt": now,
        }

        result = blogs_collection.insert_one(doc)
        doc["_id"] = result.inserted_id

        return cls._serialize_blog(doc)

    @classmethod
    def get_public_blogs(cls) -> list[dict]:
        cursor = blogs_collection.find().sort("createdAt", -1)
        return [cls._serialize_blog(doc) for doc in cursor]

    @classmethod
    def get_blog_by_id(cls, blog_id: str) -> Optional[dict]:
        try:
            doc = blogs_collection.find_one({"_id": ObjectId(blog_id)})
        except Exception:
            doc = None

        if not doc:
            return None

        return cls._serialize_blog(doc)

    @classmethod
    def update_blog(cls, blog_id: str, payload: BlogPayload) -> Optional[dict]:
        try:
            object_id = ObjectId(blog_id)
        except Exception:
            return None

        title = str(payload.title or "").strip()
        description = str(payload.description or "").strip()
        thumbnail = cls._clean_thumbnail(payload.thumbnail)

        if not title:
            raise ValueError("Title is required")

        if not description:
            raise ValueError("Description is required")

        if not thumbnail:
            raise ValueError("Thumbnail is required")

        existing = blogs_collection.find_one({"_id": object_id})
        if not existing:
            return None

        blogs_collection.update_one(
            {"_id": object_id},
            {
                "$set": {
                    "title": title,
                    "description": description,
                    "thumbnail": thumbnail,
                    "updatedAt": cls._now_iso(),
                }
            },
        )

        updated = blogs_collection.find_one({"_id": object_id})
        return cls._serialize_blog(updated)

    @classmethod
    def delete_blog(cls, blog_id: str) -> int:
        try:
            object_id = ObjectId(blog_id)
        except Exception:
            return 0

        result = blogs_collection.delete_one({"_id": object_id})
        return result.deleted_count
