"""Label Template storage + CRUD.

Template doc shape:
    {
        "_id": ObjectId,
        "company_id": str,
        "name": str,                       # human-readable (e.g. "Retail 2×1.5")
        "kind": "product" | "retail" | "barcode" | "qr" | "packing" | "shipping" | "custom",
        "size": {                          # physical dimensions
            "preset": "2x1.5" | "custom" | ...,
            "width_mm": float,
            "height_mm": float,
            "margin_mm": float,
            "gap_mm": float,
            "dpi": int,
        },
        "elements": [                       # ordered list of canvas elements
            {
                "id": str (uuid),
                "type": "text" | "field" | "barcode" | "qr" | "image" | "rect",
                "x": float,                # mm
                "y": float,                # mm
                "w": float,                # mm
                "h": float,                # mm
                "rotation": 0|90|180|270,
                # text/field
                "text": str,               # for type=text; literal text
                "field": str,              # for type=field; e.g. "product.name"
                "font_family": "Helvetica" | "Arial" | "monospace",
                "font_size": float,        # pt
                "font_weight": "normal" | "bold",
                "font_style": "normal" | "italic",
                "align": "left" | "center" | "right",
                "color": "#RRGGBB",
                # barcode/qr
                "barcode_type": "CODE128" | "CODE39" | "EAN13" | "EAN8" | "UPC" | "ITF" | "GS1",
                "barcode_value": str,       # static OR field-binding "{product.barcode}"
                "qr_value": str,
                # image
                "image_data_url": str,
            }, ...
        ],
        "is_default": bool,
        "created_by": str (email),
        "created_at": iso,
        "updated_at": iso,
    }
"""
from datetime import datetime, timezone
from typing import Optional, List, Dict, Any
from bson import ObjectId
from fastapi import APIRouter, HTTPException, Depends, Request, Query
from pydantic import BaseModel, Field

from auth import get_current_user, require_admin


router = APIRouter(prefix="/api/labels", tags=["labels"])


# ============ Helpers ============
def _oid(v: str) -> ObjectId:
    try:
        return ObjectId(v)
    except Exception:
        raise HTTPException(400, f"Invalid id: {v}")


def _ser(d: dict) -> dict:
    if not d:
        return d
    d = dict(d)
    d["id"] = str(d.pop("_id"))
    return d


def _now() -> str:
    return datetime.now(timezone.utc).isoformat()


# ============ Models ============
class LabelSize(BaseModel):
    preset: Optional[str] = "custom"
    width_mm: float = Field(50.0, gt=0, le=500)
    height_mm: float = Field(30.0, gt=0, le=500)
    margin_mm: float = Field(1.0, ge=0, le=50)
    gap_mm: float = Field(2.0, ge=0, le=50)
    dpi: int = Field(203, ge=72, le=600)


class LabelElement(BaseModel):
    id: str
    type: str                                          # text | field | barcode | qr | image | rect | line
    x: float = 0.0
    y: float = 0.0
    w: float = 10.0
    h: float = 5.0
    rotation: int = 0
    # text/field common
    text: Optional[str] = ""
    field: Optional[str] = ""                          # e.g. "product.name"
    font_family: Optional[str] = "Helvetica"
    font_size: Optional[float] = 10.0
    font_weight: Optional[str] = "normal"
    font_style: Optional[str] = "normal"
    align: Optional[str] = "left"
    color: Optional[str] = "#000000"
    border: Optional[bool] = False
    # barcode
    barcode_type: Optional[str] = "CODE128"
    barcode_value: Optional[str] = ""
    barcode_show_text: Optional[bool] = True
    # qr
    qr_value: Optional[str] = ""
    # image / shapes
    image_data_url: Optional[str] = ""
    fill: Optional[str] = ""
    stroke: Optional[str] = "#000000"
    stroke_width: Optional[float] = 0.3


class LabelTemplateIn(BaseModel):
    name: str
    kind: Optional[str] = "product"
    size: LabelSize
    elements: List[LabelElement] = []
    is_default: bool = False
    description: Optional[str] = ""


# ============ Built-in Preset Sizes (for client convenience) ============
PRESET_SIZES = [
    {"key": "0.75x1",   "label": "3/4\" × 1\"",   "width_mm": 19,  "height_mm": 25.4},
    {"key": "1x1",      "label": "1\" × 1\"",     "width_mm": 25.4, "height_mm": 25.4},
    {"key": "2x1",      "label": "2\" × 1\"",     "width_mm": 50.8, "height_mm": 25.4},
    {"key": "2x1.5",    "label": "2\" × 1.5\"",   "width_mm": 50.8, "height_mm": 38.1},
    {"key": "2x2",      "label": "2\" × 2\"",     "width_mm": 50.8, "height_mm": 50.8},
    {"key": "3x2",      "label": "3\" × 2\"",     "width_mm": 76.2, "height_mm": 50.8},
    {"key": "4x2",      "label": "4\" × 2\"",     "width_mm": 101.6, "height_mm": 50.8},
    {"key": "4x3",      "label": "4\" × 3\"",     "width_mm": 101.6, "height_mm": 76.2},
    {"key": "A4",       "label": "A4",            "width_mm": 210,  "height_mm": 297},
    {"key": "A5",       "label": "A5",            "width_mm": 148,  "height_mm": 210},
    {"key": "A6",       "label": "A6",            "width_mm": 105,  "height_mm": 148},
]

SUPPORTED_FIELDS = [
    {"key": "product.name", "label": "Product Name"},
    {"key": "product.brand", "label": "Brand Name"},
    {"key": "product.category", "label": "Category"},
    {"key": "product.size", "label": "Size"},
    {"key": "product.barcode", "label": "Barcode Value"},
    {"key": "product.sku", "label": "SKU / Code"},
    {"key": "product.hsn", "label": "HSN / SAC"},
    {"key": "product.gst_rate", "label": "GST %"},
    {"key": "product.mrp", "label": "MRP"},
    {"key": "product.sale_price", "label": "Sale Price"},
    {"key": "product.purchase_price", "label": "Purchase Price"},
    {"key": "product.batch_no", "label": "Batch No"},
    {"key": "product.packing_date", "label": "Packing Date"},
    {"key": "product.expiry_date", "label": "Expiry Date"},
    {"key": "product.manufacturer", "label": "Manufacturer"},
    {"key": "product.supplier", "label": "Supplier"},
    {"key": "product.address", "label": "Address"},
    {"key": "product.description", "label": "Description"},
    {"key": "product.unit", "label": "Unit"},
    {"key": "product.current_stock", "label": "Current Stock"},
    {"key": "company.name", "label": "Company Name"},
    {"key": "company.gstin", "label": "Company GSTIN"},
    {"key": "company.phone", "label": "Company Phone"},
    {"key": "company.address", "label": "Company Address"},
    {"key": "date.today", "label": "Today's Date"},
]

SUPPORTED_PRINTERS = [
    "TSC", "TVS", "Zebra", "XPrinter", "Citizen",
    "Honeywell", "Epson", "Rongta", "Brother", "Generic",
]


# ============ Routes ============
@router.get("/meta")
async def label_meta():
    """Static metadata for the label designer UI — preset sizes, supported fields, printers, barcode types."""
    return {
        "preset_sizes": PRESET_SIZES,
        "fields": SUPPORTED_FIELDS,
        "printers": SUPPORTED_PRINTERS,
        "barcode_types": ["CODE128", "CODE39", "EAN13", "EAN8", "UPC", "ITF", "GS1"],
        "kinds": ["product", "retail", "barcode", "qr", "packing", "shipping", "custom"],
    }


@router.get("/templates")
async def list_templates(
    request: Request,
    company_id: str = Query(...),
    kind: Optional[str] = None,
    user=Depends(get_current_user),
):
    db = request.app.state.db
    q: Dict[str, Any] = {"company_id": company_id}
    if kind:
        q["kind"] = kind
    docs = await db.label_templates.find(q).sort("updated_at", -1).to_list(500)
    return [_ser(d) for d in docs]


@router.get("/templates/{tid}")
async def get_template(tid: str, request: Request, user=Depends(get_current_user)):
    db = request.app.state.db
    doc = await db.label_templates.find_one({"_id": _oid(tid)})
    if not doc:
        raise HTTPException(404, "Template not found")
    return _ser(doc)


@router.post("/templates")
async def create_template(
    payload: LabelTemplateIn,
    request: Request,
    company_id: str = Query(...),
    user=Depends(get_current_user),
):
    db = request.app.state.db
    if not payload.name.strip():
        raise HTTPException(422, "name is required")
    # If is_default, unset existing defaults for the same kind/company
    if payload.is_default:
        await db.label_templates.update_many(
            {"company_id": company_id, "kind": payload.kind},
            {"$set": {"is_default": False}},
        )
    doc = payload.model_dump()
    doc.update({
        "company_id": company_id,
        "created_by": user["email"],
        "created_at": _now(),
        "updated_at": _now(),
    })
    res = await db.label_templates.insert_one(doc)
    saved = await db.label_templates.find_one({"_id": res.inserted_id})
    return _ser(saved)


@router.put("/templates/{tid}")
async def update_template(
    tid: str,
    payload: LabelTemplateIn,
    request: Request,
    user=Depends(get_current_user),
):
    db = request.app.state.db
    existing = await db.label_templates.find_one({"_id": _oid(tid)})
    if not existing:
        raise HTTPException(404, "Template not found")
    if payload.is_default:
        await db.label_templates.update_many(
            {"company_id": existing["company_id"], "kind": payload.kind, "_id": {"$ne": existing["_id"]}},
            {"$set": {"is_default": False}},
        )
    update = payload.model_dump()
    update["updated_at"] = _now()
    update["updated_by"] = user["email"]
    await db.label_templates.update_one({"_id": existing["_id"]}, {"$set": update})
    saved = await db.label_templates.find_one({"_id": existing["_id"]})
    return _ser(saved)


@router.delete("/templates/{tid}")
async def delete_template(tid: str, request: Request, user=Depends(require_admin)):
    db = request.app.state.db
    res = await db.label_templates.delete_one({"_id": _oid(tid)})
    if res.deleted_count == 0:
        raise HTTPException(404, "Template not found")
    return {"ok": True}


@router.post("/templates/{tid}/duplicate")
async def duplicate_template(tid: str, request: Request, user=Depends(get_current_user)):
    db = request.app.state.db
    existing = await db.label_templates.find_one({"_id": _oid(tid)})
    if not existing:
        raise HTTPException(404, "Template not found")
    new_doc = dict(existing)
    new_doc.pop("_id", None)
    new_doc["name"] = f"{existing.get('name', 'Template')} (copy)"
    new_doc["is_default"] = False
    new_doc["created_by"] = user["email"]
    new_doc["created_at"] = _now()
    new_doc["updated_at"] = _now()
    res = await db.label_templates.insert_one(new_doc)
    saved = await db.label_templates.find_one({"_id": res.inserted_id})
    return _ser(saved)


@router.get("/print-log")
async def list_print_logs(
    request: Request,
    company_id: str = Query(...),
    limit: int = Query(50, le=200),
    user=Depends(get_current_user),
):
    db = request.app.state.db
    docs = await db.label_print_logs.find({"company_id": company_id}).sort("timestamp", -1).to_list(limit)
    return [_ser(d) for d in docs]


class PrintLogIn(BaseModel):
    template_id: Optional[str] = None
    template_name: Optional[str] = ""
    item_count: int = 0
    label_count: int = 0
    copies: int = 1
    output: str = "print"      # print | pdf | png | jpeg


@router.post("/print-log")
async def log_print_job(
    payload: PrintLogIn,
    request: Request,
    company_id: str = Query(...),
    user=Depends(get_current_user),
):
    db = request.app.state.db
    doc = payload.model_dump()
    doc.update({
        "company_id": company_id,
        "user_email": user["email"],
        "timestamp": _now(),
    })
    res = await db.label_print_logs.insert_one(doc)
    return {"id": str(res.inserted_id), "ok": True}
