# Copyright 2023 Canonical Ltd.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
# For further info, check https://github.com/canonical/charmcraft

"""Infrastructure for the 'extensions' command."""
import argparse
from textwrap import dedent
from typing import Dict

import tabulate
import yaml
from craft_cli import emit

from charmcraft import extensions
from charmcraft.cmdbase import BaseCommand
from charmcraft.models.extension import ExtensionModel

_overview = """
Extensions allow user use pre-defined configuration in their charmcraft.yaml.
"""


class ListExtensionsCommand(BaseCommand):
    """List available extensions for all supported bases."""

    common = True
    name = "list-extensions"
    help_msg = "List available extensions for all supported bases"
    overview = dedent(
        """
        List available extensions and their corresponding bases.
        """
    )

    def run(self, parsed_args: argparse.Namespace):
        """Print the list of available extensions and their bases."""
        extension_presentation: Dict[str, ExtensionModel] = {}

        for extension_name in extensions.registry.get_extension_names():
            extension_class = extensions.registry.get_extension_class(extension_name)
            extension_bases = list(extension_class.get_supported_bases())
            extension_presentation[extension_name] = ExtensionModel(
                name=extension_name, bases=extension_bases
            )

        printable_extensions = sorted(
            [v.marshal() for v in extension_presentation.values()],
            key=lambda d: d["Extension name"],
        )
        emit.message(tabulate.tabulate(printable_extensions, headers="keys"))


class ExtensionsCommand(ListExtensionsCommand):
    """A command alias to list the available extensions."""

    common = False
    name = "extensions"
    hidden = True

    # Workaround for AST test that cannot see run()
    def run(self, parsed_args: argparse.Namespace):
        """Print the list of available extensions and their bases."""
        ListExtensionsCommand.run(self, parsed_args)


class ExpandExtensionsCommand(BaseCommand):
    """Expand the extensions in the charmcraft.yaml file."""

    common = True
    name = "expand-extensions"
    help_msg = "Expand extensions in charmcraft.yaml"
    overview = dedent(
        """
        Expand charmcraft.yaml using the extensions specified in the file and
        output the resulting configuration to the terminal.

        This allows you to see how the extensions used modify your existing
        charmcraft.yaml file.
        """
    )

    def run(self, parsed_args: argparse.Namespace):
        """Print the project's specification with the extensions expanded."""
        self._check_config(config_file=True)
        emit.message(
            yaml.dump(
                self.config.dict(
                    by_alias=True, exclude={"project", "metadata_legacy"}, exclude_none=True
                )
            )
        )
