"""Load canonical project state for the Cloud projection (Workstream E1). Read-only."""

from __future__ import annotations

from uuid import UUID

from sqlalchemy import select
from sqlalchemy.ext.asyncio import AsyncSession

from src.domain.project_auth.cloud_projection import (
    BindingSnapshot,
    MembershipSnapshot,
    ProjectSnapshot,
    RoleSnapshot,
)
from src.domain.project_auth.models import (
    ProjectAuthRole,
    ProjectMembership,
    ProjectMembershipRole,
    ProjectMembershipSuspension,
)


def _text(value) -> str | None:
    return None if value is None else getattr(value, "value", value)


async def load_project_snapshot(db: AsyncSession, project_id: UUID) -> ProjectSnapshot:
    role_rows = (
        await db.execute(select(ProjectAuthRole).where(ProjectAuthRole.project_id == project_id))
    ).scalars().all()
    roles = {
        r.id: RoleSnapshot(
            role_id=r.id,
            name=r.name,
            assignment_tier=_text(r.assignment_tier),
            protected=bool(r.protected),
            permissions=frozenset(r.permissions_json or []),
        )
        for r in role_rows
    }
    protected_owner_permissions = frozenset(
        p for r in role_rows if r.protected for p in (r.permissions_json or [])
    )

    member_rows = (
        await db.execute(
            select(ProjectMembership).where(ProjectMembership.project_id == project_id)
        )
    ).scalars().all()
    ids = [m.id for m in member_rows]
    bindings: dict[UUID, set[BindingSnapshot]] = {i: set() for i in ids}
    holds: dict[UUID, set[str]] = {i: set() for i in ids}
    if ids:
        for link in (
            await db.execute(
                select(ProjectMembershipRole).where(ProjectMembershipRole.membership_id.in_(ids))
            )
        ).scalars().all():
            bindings[link.membership_id].add(BindingSnapshot(link.role_id, _text(link.source)))
        for hold in (
            await db.execute(
                select(ProjectMembershipSuspension).where(
                    ProjectMembershipSuspension.membership_id.in_(ids)
                )
            )
        ).scalars().all():
            holds[hold.membership_id].add(_text(hold.source))

    memberships = tuple(
        MembershipSnapshot(
            membership_id=m.id,
            email=m.email_normalized,
            is_owner=bool(m.is_owner),
            cloud_app_user_id=m.cloud_app_user_id,
            authorization_version=int(m.authorization_version),
            bindings=frozenset(bindings[m.id]),
            holds=frozenset(holds[m.id]),
        )
        for m in member_rows
    )
    return ProjectSnapshot(
        roles=roles,
        protected_owner_permissions=protected_owner_permissions,
        memberships=memberships,
    )
