"""CRM clients + notes (lightweight CRM)."""
from datetime import datetime, timezone
from bson import ObjectId
from bson.errors import InvalidId
from fastapi import APIRouter, Depends, HTTPException, Query

from deps import get_db, get_current_user, require_roles
from models import CRMClientIn, CRMClientUpdate, CRMNoteIn, MARKETING_ROLES

router = APIRouter(prefix="/crm/clients", tags=["crm"])

_marketing = require_roles(*MARKETING_ROLES)


def _oid(s):
    try: return ObjectId(s)
    except InvalidId: raise HTTPException(status_code=400, detail="ID inválido")


def _ser(c: dict) -> dict:
    return {
        "id": str(c["_id"]),
        "name": c["name"],
        "email": c.get("email"),
        "phone": c.get("phone"),
        "company": c.get("company", ""),
        "status": c.get("status", "lead"),
        "owner_id": c.get("owner_id"),
        "notes": c.get("notes", ""),
        "tags": c.get("tags", []),
        "user_id": c.get("user_id"),
        "created_at": c.get("created_at"),
        "updated_at": c.get("updated_at"),
        "last_contact_at": c.get("last_contact_at"),
    }


@router.get("")
async def list_clients(
    q: str = Query("", description="Búsqueda libre"),
    status: str | None = None,
    owner_id: str | None = None,
    _: dict = Depends(_marketing),
):
    db = get_db()
    flt: dict = {}
    if status:
        flt["status"] = status
    if owner_id:
        flt["owner_id"] = owner_id
    if q:
        rx = {"$regex": q, "$options": "i"}
        flt["$or"] = [{"name": rx}, {"email": rx}, {"company": rx}]
    cur = db.crm_clients.find(flt).sort("created_at", -1)
    return [_ser(c) async for c in cur]


@router.post("")
async def create_client(payload: CRMClientIn, user: dict = Depends(_marketing)):
    db = get_db()
    now = datetime.now(timezone.utc).isoformat()
    doc = {**payload.model_dump(), "owner_id": payload.owner_id or user["id"], "created_at": now, "updated_at": now}
    r = await db.crm_clients.insert_one(doc)
    doc["_id"] = r.inserted_id
    return _ser(doc)


@router.get("/{client_id}")
async def get_client(client_id: str, _: dict = Depends(_marketing)):
    db = get_db()
    c = await db.crm_clients.find_one({"_id": _oid(client_id)})
    if not c: raise HTTPException(status_code=404, detail="Cliente no encontrado")
    notes_cur = db.crm_client_notes.find({"client_id": client_id}).sort("created_at", -1)
    notes = [{
        "id": str(n["_id"]),
        "body": n["body"],
        "author_id": n.get("author_id"),
        "author_name": n.get("author_name"),
        "created_at": n["created_at"],
    } async for n in notes_cur]
    return {**_ser(c), "activity_notes": notes}


@router.patch("/{client_id}")
async def update_client(client_id: str, payload: CRMClientUpdate, _: dict = Depends(_marketing)):
    db = get_db()
    update = {k: v for k, v in payload.model_dump(exclude_unset=True).items()}
    if not update: raise HTTPException(status_code=400, detail="Nada para actualizar")
    update["updated_at"] = datetime.now(timezone.utc).isoformat()
    r = await db.crm_clients.find_one_and_update({"_id": _oid(client_id)}, {"$set": update}, return_document=True)
    if not r: raise HTTPException(status_code=404, detail="Cliente no encontrado")
    return _ser(r)


@router.delete("/{client_id}")
async def delete_client(client_id: str, _: dict = Depends(require_roles("ceo", "admin"))):
    db = get_db()
    r = await db.crm_clients.delete_one({"_id": _oid(client_id)})
    await db.crm_client_notes.delete_many({"client_id": client_id})
    if r.deleted_count == 0: raise HTTPException(status_code=404, detail="Cliente no encontrado")
    return {"ok": True}


@router.post("/{client_id}/notes")
async def add_note(client_id: str, payload: CRMNoteIn, user: dict = Depends(_marketing)):
    db = get_db()
    if not await db.crm_clients.find_one({"_id": _oid(client_id)}):
        raise HTTPException(status_code=404, detail="Cliente no encontrado")
    now = datetime.now(timezone.utc).isoformat()
    doc = {
        "client_id": client_id, "body": payload.body,
        "author_id": user["id"], "author_name": user.get("name", ""), "created_at": now,
    }
    r = await db.crm_client_notes.insert_one(doc)
    await db.crm_clients.update_one({"_id": _oid(client_id)}, {"$set": {"last_contact_at": now, "updated_at": now}})
    return {"id": str(r.inserted_id), **{k: v for k, v in doc.items() if k != "_id"}}
