# Copyright (C) 2012 Anaconda, Inc
# SPDX-License-Identifier: BSD-3-Clause
from __future__ import annotations

from functools import partial
import os

from ..base.context import context, locate_prefix_by_name, validate_prefix_name
from ..base.constants import DRY_RUN_PREFIX
from ..cli import common, install
from ..common.path import expand, paths_equal
from ..exceptions import CondaEnvException
from ..gateways.disk.delete import rm_rf
from ..gateways.disk.update import rename_context


def validate_src(name: str | None, prefix: str | None) -> str:
    """
    Validate that we are receiving at least one value for --name or --prefix
    and ensure that the "base" environment is not being renamed
    """
    if paths_equal(context.target_prefix, context.root_prefix):
        raise CondaEnvException("The 'base' environment cannot be renamed")

    prefix = name or prefix

    if common.is_active_prefix(prefix):
        raise CondaEnvException("Cannot rename the active environment")

    return locate_prefix_by_name(prefix)


def validate_destination(dest: str, force: bool = False) -> str:
    """Ensure that our destination does not exist"""
    if os.sep in dest:
        dest = expand(dest)
    else:
        dest = validate_prefix_name(dest, ctx=context, allow_base=False)

    if not force and os.path.exists(dest):
        env_name = os.path.basename(os.path.normpath(dest))
        raise CondaEnvException(
            f"The environment '{env_name}' already exists. Override with --force."
        )
    return dest


def execute(args, _):
    """
    Executes the command for renaming an existing environment
    """
    source = validate_src(args.name, args.prefix)
    destination = validate_destination(args.destination, force=args.force)

    def clone_and_remove():
        actions: tuple[partial, ...] = (
            partial(install.clone, source, destination, quiet=context.quiet, json=context.json),
            partial(rm_rf, source),
        )

        # We now either run collected actions or print dry run statement
        for func in actions:
            if args.dry_run:
                print(f"{DRY_RUN_PREFIX} {func.func.__name__} {','.join(func.args)}")
            else:
                func()

    if args.force:
        with rename_context(destination, dry_run=args.dry_run):
            clone_and_remove()
    else:
        clone_and_remove()
