"""Grant the staff role to an existing membership in the AuthV2 Golden Complex fixture.

Creates the multi-role case for the certification fixture: one member holds the workspace-sourced
admin role and a local staff role. Runs as the system (no actor membership), records an audit
event, and is idempotent.

Guards:
- Only the project named "AuthV2 Golden Complex" is accepted, so this cannot touch customer
  projects.
- Dry run is the default. Nothing is written without --apply.
- The target membership must already exist in the project.

Usage (P2HS-BE root, same .env as the API):

    python -m scripts.authz_v2_golden_complex_grant_staff --project-id <uuid> --email <email>
    python -m scripts.authz_v2_golden_complex_grant_staff --project-id <uuid> --email <email> --apply

Exit code is 0 when the grant is present after the run (applied or already present), 1 otherwise.
"""

from __future__ import annotations

import argparse
import asyncio
import sys
from uuid import UUID

from src.core.orm_import import import_all_orm_models

import_all_orm_models()

FIXTURE_NAME = "AuthV2 Golden Complex"
ROLE_NAME = "staff"
EVENT = "project.member.role_granted_fixture"


async def _run(project_id: UUID, email: str, apply: bool) -> int:
    from sqlalchemy import select

    from src.core.database import async_session_factory
    from src.domain.project_auth.audit import record_event
    from src.domain.project_auth.models import (
        MembershipRoleSource,
        ProjectAuthRole,
        ProjectMembership,
        ProjectMembershipRole,
    )
    from src.domain.projects.models import Project

    email_normalized = email.strip().lower()
    async with async_session_factory() as db:
        try:
            project = (await db.execute(select(Project).where(Project.id == project_id))).scalar_one_or_none()
            if project is None or project.name != FIXTURE_NAME:
                print(f"[error] project {project_id} is not the {FIXTURE_NAME!r} fixture", file=sys.stderr)
                return 2

            membership = (await db.execute(
                select(ProjectMembership).where(
                    ProjectMembership.project_id == project_id,
                    ProjectMembership.email_normalized == email_normalized,
                )
            )).scalar_one_or_none()
            if membership is None:
                print(f"[error] no membership for {email_normalized} in {project_id}", file=sys.stderr)
                return 2

            role = (await db.execute(
                select(ProjectAuthRole).where(
                    ProjectAuthRole.project_id == project_id, ProjectAuthRole.name == ROLE_NAME,
                )
            )).scalar_one_or_none()
            if role is None:
                print(f"[error] role {ROLE_NAME!r} not found in {project_id}", file=sys.stderr)
                return 2

            existing = (await db.execute(
                select(ProjectMembershipRole).where(
                    ProjectMembershipRole.membership_id == membership.id,
                    ProjectMembershipRole.role_id == role.id,
                    ProjectMembershipRole.source == MembershipRoleSource.local,
                )
            )).scalar_one_or_none()

            if existing is not None:
                print(f"ALREADY_PRESENT  {email_normalized} {ROLE_NAME} (source=local)")
                return 0

            if not apply:
                print(f"WOULD_GRANT      {email_normalized} {ROLE_NAME} (source=local)")
                print("\n[DRY RUN] 0 written.")
                return 0

            db.add(ProjectMembershipRole(
                membership_id=membership.id, role_id=role.id, source=MembershipRoleSource.local,
            ))
            await record_event(
                db,
                project_id=project_id,
                event=EVENT,
                actor_membership_id=None,
                target_membership_id=membership.id,
                payload={"role": ROLE_NAME, "source": "local", "reason": "authz_v2_golden_complex_case"},
                correlation_id=None,
            )
            await db.commit()
            print(f"GRANTED          {email_normalized} {ROLE_NAME} (source=local)")
            print("\n[APPLY] 1 written.")
            return 0
        except Exception:
            await db.rollback()
            raise


def main() -> None:
    parser = argparse.ArgumentParser(description=__doc__.splitlines()[0])
    parser.add_argument("--project-id", type=UUID, required=True)
    parser.add_argument("--email", required=True)
    parser.add_argument("--apply", action="store_true", help="write the grant (default: dry run)")
    args = parser.parse_args()
    sys.exit(asyncio.run(_run(args.project_id, args.email, args.apply)))


if __name__ == "__main__":
    main()
