# Copyright 2024 The Debusine Developers
# See the AUTHORS file at the top-level directory of this distribution
#
# This file is part of Debusine. It is subject to the license terms
# in the LICENSE file found in the top-level directory of this
# distribution. No part of Debusine, including this file, may be copied,
# modified, propagated, or distributed except according to the terms
# contained in the LICENSE file.

"""debusine-admin command to rename scopes."""

from collections.abc import Callable
from typing import NoReturn, cast

from django.core.exceptions import ValidationError
from django.core.management import CommandError

from debusine.db.models import Scope
from debusine.django.management.debusine_base_command import DebusineBaseCommand


class Command(DebusineBaseCommand):
    """Command to manage scopes."""

    help = "Manage scopes"

    def add_arguments(self, parser):
        """Add CLI arguments."""
        subparsers = parser.add_subparsers(dest="action", required=True)

        rename = subparsers.add_parser("rename")
        rename.add_argument("scope", help="Scope to rename")
        rename.add_argument("name", help="New name for the scope")

    def get_scope(self, name: str) -> Scope:
        """Lookup a scope by name."""
        try:
            return Scope.objects.get(name=name)
        except Scope.DoesNotExist:
            raise CommandError(f"Scope {name!r} not found", returncode=3)

    def handle(self, *args, **options) -> NoReturn:
        """Dispatch the requested action."""
        func = cast(
            Callable[..., NoReturn],
            getattr(self, f"handle_{options['action']}", None),
        )
        if func is None:
            raise CommandError(
                f"Action {options['action']!r} not found", returncode=3
            )

        func(*args, **options)

    def handle_rename(self, *, scope: str, name: str, **options) -> NoReturn:
        """Rename a scope."""
        s = self.get_scope(scope)

        if name == s.name:
            raise SystemExit(0)

        s.name = name
        try:
            s.full_clean()
        except ValidationError as exc:
            self.stderr.write("Renamed scope would be invalid:")
            for field, errors in exc.message_dict.items():
                for error in errors:
                    self.stderr.write(f"* {field}: {error}")
            raise SystemExit(3)

        s.save()

        raise SystemExit(0)
