"""Membership service — queries the memberships collection."""

from datetime import UTC, datetime

from motor.motor_asyncio import AsyncIOMotorDatabase

from ..models.membership import MemberDetail, Membership
from ..models.organization import OrgRole


def _now() -> datetime:
    return datetime.now(UTC)


def _membership_from_doc(doc: dict) -> Membership:
    raw_role = doc.get("role_in_org", "member")
    try:
        role = OrgRole(raw_role)
    except ValueError:
        role = OrgRole.MEMBER
    return Membership(
        id=str(doc["_id"]),
        user_id=doc.get("user_id", ""),
        organization_id=doc.get("organization_id", ""),
        role_in_org=role,
        created_at=doc.get("created_at"),
        created_by=doc.get("created_by"),
    )


async def get_memberships_for_user(
    user_id: str,
    db: AsyncIOMotorDatabase,
) -> list[Membership]:
    cursor = db.memberships.find({"user_id": user_id})
    return [_membership_from_doc(doc) async for doc in cursor]


async def get_membership(
    user_id: str,
    organization_id: str,
    db: AsyncIOMotorDatabase,
) -> Membership | None:
    doc = await db.memberships.find_one(
        {"user_id": user_id, "organization_id": organization_id}
    )
    return _membership_from_doc(doc) if doc else None


async def has_org_role(
    user_id: str,
    organization_id: str,
    min_role: OrgRole,
    db: AsyncIOMotorDatabase,
) -> bool:
    membership = await get_membership(user_id, organization_id, db)
    if membership is None:
        return False
    return membership.role_in_org >= min_role


async def upsert_membership(
    user_id: str,
    organization_id: str,
    role_in_org: OrgRole,
    created_by: str | None,
    db: AsyncIOMotorDatabase,
) -> Membership:
    now = _now()
    result = await db.memberships.find_one_and_update(
        {"user_id": user_id, "organization_id": organization_id},
        {
            "$set": {"role_in_org": role_in_org.value, "updated_at": now},
            "$setOnInsert": {
                "user_id": user_id,
                "organization_id": organization_id,
                "created_at": now,
                "created_by": created_by,
            },
        },
        upsert=True,
        return_document=True,
    )
    return _membership_from_doc(result)


async def remove_membership(
    user_id: str,
    organization_id: str,
    db: AsyncIOMotorDatabase,
) -> bool:
    result = await db.memberships.delete_one(
        {"user_id": user_id, "organization_id": organization_id}
    )
    return result.deleted_count > 0


async def list_org_members(
    organization_id: str,
    db: AsyncIOMotorDatabase,
) -> list[MemberDetail]:
    pipeline = [
        {"$match": {"organization_id": organization_id}},
        {
            "$lookup": {
                "from": "users",
                "localField": "user_id",
                "foreignField": "_id",
                "as": "user_doc",
            }
        },
        {"$unwind": {"path": "$user_doc", "preserveNullAndEmptyArrays": False}},
        {"$sort": {"created_at": 1}},
    ]
    details = []
    async for doc in db.memberships.aggregate(pipeline):
        u = doc["user_doc"]
        raw_role = doc.get("role_in_org", "member")
        try:
            role = OrgRole(raw_role)
        except ValueError:
            role = OrgRole.MEMBER
        details.append(
            MemberDetail(
                membership_id=str(doc["_id"]),
                user_id=doc.get("user_id", ""),
                email=u.get("email") or "",
                full_name=u.get("full_name") or "",
                role_in_org=role,
                created_at=doc.get("created_at"),
            )
        )
    return details
