from pydantic import BaseModel, Field
from typing import List, Optional
from pymongo import MongoClient


class DesignTemplate(BaseModel):
    width: float
    height: float
    dpi: int


class Color(BaseModel):
    name: str = Field(..., min_length=1)
    hex: str = Field(..., min_length=1)


class StyleEntry(BaseModel):
    name: str = Field(..., min_length=1)
    thumbnail: Optional[str] = ""


class Variant(BaseModel):
    color: Optional[str] = ""
    style: str = Field(..., min_length=1)
    size: str = Field(..., min_length=1)
    price: float


class ShippingRate(BaseModel):
    region: str
    transitTime: str
    cost: float
    importTax: Optional[float] = 0.0
    importTaxNote: Optional[str] = ""


class SizeGuide(BaseModel):
    size: str
    lengthInch: float
    widthInch: float
    lengthCm: float
    widthCm: float


class ProductPayload(BaseModel):
    id: str
    title: str
    categoryName: str
    subCategory: Optional[str] = None
    price: float
    description: Optional[str] = ""
    badge: str = ""
    badgeColor: str = "#3b82f6"
    images: List[str]
    designTemplate: DesignTemplate
    sizes: List[str] = []
    colors: List[Color] = []
    styles: List[StyleEntry] = []
    variants: List[Variant] = []
    shippingRates: List[ShippingRate] = []
    sizeGuide: List[SizeGuide] = []


class ProductDatabaseModel:
    def __init__(self, db_uri: str, db_name: str, collection_name: str):
        self.client = MongoClient(db_uri)
        self.db = self.client[db_name]
        self.collection = self.db[collection_name]

    def insert_product(self, product_data: dict) -> str:
        frontend_id = product_data.pop("id", "").strip()
        title = product_data.get("title", "").strip()

        if not frontend_id:
            raise ValueError("ERR_EMPTY_ID")

        if self.collection.find_one({"productId": frontend_id}):
            raise ValueError("ERR_DUPLICATE_ID")

        if self.collection.find_one({"title": title}):
            raise ValueError("ERR_DUPLICATE_TITLE")

        product_data["description"] = product_data.get("description", "") or ""
        product_data["colors"] = product_data.get("colors", []) or []
        product_data["styles"] = product_data.get("styles", []) or []
        product_data["variants"] = product_data.get("variants", []) or []
        product_data["shippingRates"] = product_data.get("shippingRates", []) or []
        product_data["sizeGuide"] = product_data.get("sizeGuide", []) or []

        ordered_data = {
            "productId": frontend_id,
            **product_data,
        }

        try:
            result = self.collection.insert_one(ordered_data)
            return str(result.inserted_id)
        except Exception:
            raise Exception("ERR_DATABASE_SYSTEM")