"""User activation flow + password change."""
import os
import secrets
from datetime import datetime, timezone, timedelta
from bson import ObjectId
from bson.errors import InvalidId
from fastapi import APIRouter, Depends, HTTPException, Response

from auth import hash_password, verify_password, create_access_token, create_refresh_token, set_auth_cookies
from deps import get_db, get_current_user
from models import ActivateIn, ChangePasswordIn

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


@router.get("/activation/{token}")
async def get_activation(token: str):
    db = get_db()
    user = await db.users.find_one({"activation_token": token})
    if not user:
        raise HTTPException(status_code=404, detail="Token inválido o expirado")
    exp = user.get("activation_expires_at")
    if exp and datetime.now(timezone.utc).isoformat() > exp:
        raise HTTPException(status_code=410, detail="Token expirado")
    return {
        "email": user["email"],
        "name": user.get("name", ""),
        "role": user.get("role"),
        "valid": True,
    }


@router.post("/activate")
async def activate(payload: ActivateIn, response: Response):
    db = get_db()
    user = await db.users.find_one({"activation_token": payload.token})
    if not user:
        raise HTTPException(status_code=404, detail="Token inválido")
    exp = user.get("activation_expires_at")
    if exp and datetime.now(timezone.utc).isoformat() > exp:
        raise HTTPException(status_code=410, detail="Token expirado")
    await db.users.update_one(
        {"_id": user["_id"]},
        {
            "$set": {
                "password_hash": hash_password(payload.new_password),
                "active": True,
                "must_change_password": False,
                "activated_at": datetime.now(timezone.utc).isoformat(),
            },
            "$unset": {"activation_token": "", "activation_expires_at": ""},
        },
    )
    # auto-login
    uid = str(user["_id"])
    access = create_access_token(uid, user["email"], user["role"])
    refresh = create_refresh_token(uid)
    set_auth_cookies(response, access, refresh)
    return {
        "id": uid,
        "email": user["email"],
        "name": user.get("name", ""),
        "role": user.get("role"),
    }


@router.post("/change-password")
async def change_password(payload: ChangePasswordIn, user: dict = Depends(get_current_user)):
    db = get_db()
    try:
        oid = ObjectId(user["id"])
    except InvalidId:
        raise HTTPException(status_code=400, detail="ID inválido")
    full = await db.users.find_one({"_id": oid})
    if not full or not verify_password(payload.current_password, full["password_hash"]):
        raise HTTPException(status_code=400, detail="Contraseña actual incorrecta")
    await db.users.update_one(
        {"_id": oid},
        {"$set": {"password_hash": hash_password(payload.new_password), "must_change_password": False}},
    )
    return {"ok": True}


def generate_random_password(length: int = 14) -> str:
    """Generate a strong random password."""
    alphabet = "abcdefghjkmnpqrstuvwxyzABCDEFGHJKLMNPQRSTUVWXYZ23456789!@#$%&*"
    return "".join(secrets.choice(alphabet) for _ in range(length))


def generate_activation_token() -> str:
    return secrets.token_urlsafe(32)


def activation_link(token: str) -> str:
    base = os.environ.get("FRONTEND_URL", "https://quinto-sueno.preview.emergentagent.com").rstrip("/")
    return f"{base}/activate/{token}"
