import uuid
from datetime import datetime, timezone
from pymongo import ReturnDocument
from pymongo.asynchronous.database import AsyncDatabase
from app.utils.security import hash_password

async def create_agent(
    db: AsyncDatabase,
    email: str,
    password: str,
    name: str,
    role: str = "AGENT",
    status: str = "ACTIVE"
) -> dict:
    """
    Creates a new agent record in MongoDB with a hashed password.
    """
    normalized_email = email.strip().lower()
    agent_id = f"agent_{uuid.uuid4().hex[:12]}"
    now = datetime.now(timezone.utc)
    
    agent_doc = {
        "agentId": agent_id,
        "name": name,
        "email": normalized_email,
        "passwordHash": hash_password(password),
        "role": role if role in ("AGENT", "ADMIN") else "AGENT",
        "status": status if status in ("ACTIVE", "INACTIVE") else "ACTIVE",
        "createdAt": now,
        "updatedAt": now
    }
    
    await db["agents"].insert_one(agent_doc)
    return agent_doc

async def get_agent_by_email(db: AsyncDatabase, email: str) -> dict | None:
    """Finds an agent by normalized email address."""
    if not email:
        return None
    return await db["agents"].find_one({"email": email.strip().lower()})

async def get_agent_by_id(db: AsyncDatabase, agent_id: str) -> dict | None:
    """Finds an agent by unique agentId."""
    if not agent_id:
        return None
    return await db["agents"].find_one({"agentId": agent_id})

async def list_agents(db: AsyncDatabase) -> list[dict]:
    """Lists all registered agents in MongoDB."""
    cursor = db["agents"].find({})
    if hasattr(cursor, "to_list"):
        return await cursor.to_list(length=1000)
    else:
        return [doc async for doc in cursor]

async def count_active_admins(db: AsyncDatabase) -> int:
    """Counts active ADMIN accounts to prevent accidental lockout."""
    cursor = db["agents"].find({"role": "ADMIN", "status": "ACTIVE"})
    if hasattr(cursor, "to_list"):
        docs = await cursor.to_list(length=1000)
        return len(docs)
    else:
        docs = [doc async for doc in cursor]
        return len(docs)

async def update_agent(db: AsyncDatabase, agent_id: str, update_fields: dict) -> dict | None:
    """
    Updates safe fields (name, role, status) for an agent.
    Filters out passwordHash, agentId, createdAt from direct update payload.
    """
    allowed_keys = {"name", "role", "status"}
    filtered_updates = {k: v for k, v in update_fields.items() if k in allowed_keys and v is not None}
    
    if not filtered_updates:
        return await get_agent_by_id(db, agent_id)

    filtered_updates["updatedAt"] = datetime.now(timezone.utc)

    return await db["agents"].find_one_and_update(
        {"agentId": agent_id},
        {"$set": filtered_updates},
        return_document=ReturnDocument.AFTER
    )

async def reset_agent_password(db: AsyncDatabase, agent_id: str, new_password: str) -> dict | None:
    """
    Hashes and updates an agent's password atomically.
    """
    if not new_password:
        return None

    new_hash = hash_password(new_password)
    now = datetime.now(timezone.utc)

    return await db["agents"].find_one_and_update(
        {"agentId": agent_id},
        {
            "$set": {
                "passwordHash": new_hash,
                "updatedAt": now
            }
        },
        return_document=ReturnDocument.AFTER
    )
