"""Backfill / reconcile IILMP→Moodle role projections.

Assigns the mapped Moodle system role (``settings.MOODLE_ROLE_MAP``) for every
IILMP user whose role maps; with ``--demote`` also strips IILMP-managed Moodle
roles (manager / course creator) from linked users whose IILMP role no longer
maps — the piece the login-time sync deliberately never does.

Safe to re-run (assign/unassign are idempotent). Nightly cron + after role
changes in IILMP user management.
"""
from __future__ import annotations

from django.contrib.auth import get_user_model
from django.core.management.base import BaseCommand
from django.db.models import Q

from apps.core.authentication import moodle_roles


class Command(BaseCommand):
    help = "Project IILMP roles onto Moodle system roles (assign; --demote also revokes)."

    def add_arguments(self, parser):
        parser.add_argument(
            "--demote",
            action="store_true",
            help="Also unassign IILMP-managed Moodle roles from linked users whose "
            "IILMP role no longer maps (default is assign-only).",
        )
        parser.add_argument("--email", help="Sync a single user by email.")
        parser.add_argument(
            "--dry-run",
            action="store_true",
            help="Report what would change without calling Moodle.",
        )

    def handle(self, *args, **opts):
        User = get_user_model()
        demote = opts["demote"]

        if opts["email"]:
            users = User.objects.filter(email__iexact=opts["email"])
            if not users.exists():
                self.stderr.write(self.style.ERROR(f"No user with email {opts['email']}"))
                return
        else:
            mapped_roles = list(moodle_roles.settings.MOODLE_ROLE_MAP)
            scope = Q(role__in=mapped_roles)
            if demote:
                # Linked accounts (lms_ref) may hold a managed role to revoke.
                scope |= Q(lms_ref__isnull=False)
            users = User.objects.filter(scope, is_active=True)

        counts: dict[str, int] = {}
        client = moodle_roles.MoodleClient() if not opts["dry_run"] else None
        for user in users.iterator():
            desired = moodle_roles.desired_moodle_role(user)
            if opts["dry_run"]:
                outcome = f"would-{'assign:' + desired if desired else 'demote' if demote else 'skip'}"
                self.stdout.write(f"  {user.email}: {outcome}")
            else:
                try:
                    outcome = moodle_roles.sync_user(user, demote=demote, client=client)
                except moodle_roles.MoodleError as exc:
                    outcome = "error"
                    self.stderr.write(self.style.WARNING(f"  {user.email}: {exc}"))
            counts[outcome] = counts.get(outcome, 0) + 1

        summary = ", ".join(f"{k}={v}" for k, v in sorted(counts.items())) or "nothing to do"
        self.stdout.write(self.style.SUCCESS(f"sync_moodle_roles: {summary}"))
