"""Proposal requests — submitted from client portal."""
from datetime import datetime, timezone
from bson import ObjectId
from bson.errors import InvalidId
from fastapi import APIRouter, Depends, HTTPException

from deps import get_db, get_current_user, require_roles
from models import ProposalIn, ProposalUpdate
import notifications as notif

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

# Roles that can view / manage incoming proposals
PROPOSAL_VIEWERS = ("ceo", "admin", "pmo", "pm", "sales", "account_manager")


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


def _ser(p: dict) -> dict:
    return {
        "id": str(p["_id"]),
        "title": p["title"],
        "description": p["description"],
        "budget_range": p.get("budget_range", ""),
        "timeline": p.get("timeline", ""),
        "status": p.get("status", "pending"),
        "client_id": p.get("client_id"),
        "client_name": p.get("client_name", ""),
        "client_email": p.get("client_email", ""),
        "assigned_to_id": p.get("assigned_to_id"),
        "response": p.get("response", ""),
        "created_at": p.get("created_at"),
        "updated_at": p.get("updated_at"),
    }


@router.post("")
async def submit_proposal(payload: ProposalIn, user: dict = Depends(get_current_user)):
    if user["role"] != "client":
        raise HTTPException(status_code=403, detail="Solo los clientes pueden enviar propuestas")
    db = get_db()
    now = datetime.now(timezone.utc).isoformat()
    doc = {
        **payload.model_dump(),
        "status": "pending",
        "client_id": user["id"],
        "client_name": user.get("name", ""),
        "client_email": user.get("email", ""),
        "created_at": now,
        "updated_at": now,
    }
    r = await db.proposals.insert_one(doc)
    doc["_id"] = r.inserted_id
    # notify all viewers
    viewer_ids = [str(u["_id"]) async for u in db.users.find({"role": {"$in": list(PROPOSAL_VIEWERS)}}, {"_id": 1})]
    await notif.push(
        viewer_ids,
        "proposal_new",
        f"Nueva propuesta: {payload.title}",
        f"de {user.get('name', '')}",
        link="/app/propuestas",
        meta={"proposal_id": str(r.inserted_id)},
    )
    return _ser(doc)


@router.get("")
async def list_proposals(user: dict = Depends(get_current_user)):
    db = get_db()
    if user["role"] == "client":
        flt = {"client_id": user["id"]}
    elif user["role"] in PROPOSAL_VIEWERS:
        flt = {}
    else:
        raise HTTPException(status_code=403, detail="Sin acceso")
    cur = db.proposals.find(flt).sort("created_at", -1)
    return [_ser(p) async for p in cur]


@router.patch("/{pid}")
async def update_proposal(pid: str, payload: ProposalUpdate, _: dict = Depends(require_roles(*PROPOSAL_VIEWERS))):
    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.proposals.find_one_and_update({"_id": _oid(pid)}, {"$set": update}, return_document=True)
    if not r: raise HTTPException(status_code=404, detail="No encontrada")
    # notify client about status change
    if payload.status and r.get("client_id"):
        await notif.push(
            [r["client_id"]],
            "proposal_new",
            f"Actualización de tu propuesta: {r['title']}",
            f"Nuevo estado: {payload.status}",
            link="/portal",
            meta={"proposal_id": pid},
        )
    return _ser(r)


@router.delete("/{pid}")
async def delete_proposal(pid: str, _: dict = Depends(require_roles("ceo", "admin"))):
    db = get_db()
    r = await db.proposals.delete_one({"_id": _oid(pid)})
    if r.deleted_count == 0: raise HTTPException(status_code=404, detail="No encontrada")
    return {"ok": True}
