"""Distribution group management.""" from __future__ import annotations from sqlalchemy import func, select from sqlalchemy.ext.asyncio import AsyncSession from sqlalchemy.orm import selectinload from app.models import Account, MailGroup, MailGroupMember from app.schemas import MailGroupCreate, MailGroupRead def _group_read(group: MailGroup) -> MailGroupRead: return MailGroupRead( id=group.id, name=group.name, email=group.email, group_type=group.group_type, member_count=len(group.members), created_at=group.created_at, ) async def list_mail_groups( session: AsyncSession, company_domain: str, ) -> tuple[list[MailGroupRead], dict[str, int]]: result = await session.scalars( select(MailGroup) .options(selectinload(MailGroup.members)) .where(MailGroup.company_domain == company_domain) .order_by(MailGroup.created_at.desc()) ) groups = list(result.all()) items = [_group_read(group) for group in groups] counts = { "all": len(items), "distribution": sum(1 for item in items if item.group_type == "distribution"), "dynamic": sum(1 for item in items if item.group_type == "dynamic"), } return items, counts async def _validate_member_ids( session: AsyncSession, company_domain: str, member_ids: list, ) -> list[Account]: if not member_ids: return [] result = await session.scalars( select(Account).where( Account.id.in_(member_ids), Account.company_domain == company_domain, Account.member_status != "suspended", ) ) members = list(result.all()) if len(members) != len(set(member_ids)): raise ValueError("One or more selected members are invalid.") return members async def create_mail_group( session: AsyncSession, *, manager: Account, payload: MailGroupCreate, ) -> MailGroupRead: company_domain = manager.company_domain if company_domain is None: raise ValueError("Company domain is required.") email = str(payload.email).lower() if not email.endswith(f"@{company_domain}"): raise ValueError(f"Group email must use @{company_domain}.") existing = await session.scalar( select(MailGroup).where(func.lower(MailGroup.email) == email) ) if existing: raise ValueError("That group email address is already in use.") members = await _validate_member_ids( session, company_domain, payload.member_ids, ) group = MailGroup( company_domain=company_domain, name=payload.name.strip(), email=email, group_type=payload.group_type, created_by_id=manager.id, ) session.add(group) await session.flush() for member in members: session.add( MailGroupMember( group_id=group.id, account_id=member.id, ) ) await session.flush() await session.refresh(group, attribute_names=["members"]) return _group_read(group)