import itertools
from pathlib import Path
from shutil import rmtree

import click

from vantage6.common import error, warning
from vantage6.common.globals import InstanceType

from vantage6.cli.common.remove import execute_remove
from vantage6.cli.configuration_create import select_configuration_questionnaire
from vantage6.cli.context import get_context
from vantage6.cli.context.node import NodeContext
from vantage6.cli.globals import InfraComponentName
from vantage6.cli.hub.remove import cli_hub_remove


@click.command()
@click.option("-n", "--name", default=None, help="Name of the configuration.")
@click.option(
    "--data-dir",
    "custom_data_dir",
    type=click.Path(exists=True),
    default=None,
    help="Path to a custom data directory to use. This option is especially useful "
    "on WSL because of mount issues for default directories. Use the same value as "
    "was provided when creating the sandbox.",
)
@click.pass_context
def cli_sandbox_remove(
    click_ctx: click.Context,
    name: str | None,
    custom_data_dir: Path | None,
) -> None:
    """Remove all related demo network files and folders.

    Select a hub configuration to remove. The related sandbox components will also be
    removed.
    """

    if not name:
        try:
            name = select_configuration_questionnaire(
                type_=InstanceType.HUB, system_folders=False, is_sandbox=True
            )
        except Exception:
            error("No configurations could be found!")
            exit()

    ctx = get_context(InstanceType.HUB, name, system_folders=False, is_sandbox=True)

    # remove the nodes
    NodeContext.LOGGING_ENABLED = False
    configs, _ = NodeContext.available_configurations(system_folders=False)
    node_names = [
        config.name for config in configs if config.name.startswith(f"{ctx.name}-node-")
    ]
    for name in node_names:
        # Context clases are singletons, so we need to clear the cache to force
        # creation of a new instance. Otherwise, we *think* we get the ctx of another
        # node but we actually get the one from the previous node in the loop.
        if NodeContext in NodeContext._instances:
            del NodeContext._instances[NodeContext]

        node_ctx = NodeContext(
            instance_name=name,
            system_folders=False,
            is_sandbox=True,
            print_log_header=False,
            logger_prefix="",
            in_container=False,
        )
        for handler in itertools.chain(
            node_ctx.log.handlers, node_ctx.log.root.handlers
        ):
            handler.close()
        execute_remove(
            node_ctx,
            InstanceType.NODE,
            InfraComponentName.NODE,
            name,
            system_folders=False,
            force=True,
        )

    # remove data files attached to the network
    data_dirs_nodes = NodeContext.instance_folders("node", "", False)["dev"]
    try:
        rmtree(Path(data_dirs_nodes / ctx.name))
    except Exception as e:
        warning(f"Failed to delete data directory {data_dirs_nodes / ctx.name}: {e}")

    # remove the hub last - if anything goes wrong, the hub is still there so the
    # user can still retry the removal.
    # Note that this also checks if the hub is running. Therefore, it is prevented
    # that a running sandbox is removed.
    for handler in itertools.chain(ctx.log.handlers, ctx.log.root.handlers):
        handler.close()
    click_ctx.invoke(
        cli_hub_remove, ctx=ctx, name=name, system_folders=False, force=True
    )

    # remove the right data in the custom data directory if it is provided. If a custom
    # data directory is provided, all files related to the sandbox have been stored in
    # a subfolder with the name of the sandbox.
    if custom_data_dir:
        sandbox_data_dir = custom_data_dir / ctx.name
        if sandbox_data_dir.is_dir():
            rmtree(sandbox_data_dir)
