# Copyright (c) Alibaba, Inc. and its affiliates.
"""Clear-cache CLI command — retained for backward compatibility.

The ``modelscope_hub`` CLI now owns ``clear-cache`` as an alias for
``cache clear``, but this module preserves the legacy :class:`ClearCacheCMD`
class so that existing tests and callers that import it directly continue
to work.
"""
import os
import shutil
from argparse import ArgumentParser

from modelscope.cli.base import CLICommand
from modelscope.hub.constants import TEMPORARY_FOLDER_NAME
from modelscope.utils.file_utils import (get_dataset_cache_root,
                                         get_model_cache_root,
                                         get_modelscope_cache_dir)


def subparser_func(args):
    """ Function which will be called for a specific sub parser.
    """
    return ClearCacheCMD(args)


class ClearCacheCMD(CLICommand):
    name = 'clear-cache'

    def __init__(self, args):
        self.args = args
        self.cache_dir = get_modelscope_cache_dir()

    @staticmethod
    def register(subparsers) -> None:
        """Register clear-cache subcommand (CLICommand ABC contract)."""
        ClearCacheCMD.define_args(subparsers)

    @staticmethod
    def define_args(parsers: ArgumentParser):
        """ define args for clear-cache command.
        """
        parser = parsers.add_parser(ClearCacheCMD.name)
        group = parser.add_mutually_exclusive_group()
        group.add_argument(
            '--model',
            type=str,
            help='The id of the model whose cache will be cleared. '
            'If neither model or dataset id is provided, entire cache '
            'will be cleared.')
        group.add_argument(
            '--dataset',
            type=str,
            help='The id of the dataset whose cache will be cleared. '
            'If neither model or dataset id is provided, entire cache '
            'will be cleared.')

        parser.set_defaults(func=subparser_func)

    def execute(self):
        self._execute_with_confirmation()

    def _execute_with_confirmation(self):
        all = False
        single_model = False
        prompt = '\nYou are about to delete '

        if self.args.model or self.args.dataset:
            if self.args.model:
                id = self.args.model
                single_model = True
                prompt = prompt + f'local cache for model {id}. '
            else:
                id = self.args.dataset
                prompt = prompt + f'local cache for dataset {id}. '
        else:
            prompt = prompt + (f'entire ModelScope cache at {self.cache_dir}, '
                               f'including ALL models and dataset.\n')
            all = True
        user_input = input(
            prompt
            + '\nPlease press Y or y to proceed, any other key to abort.\n'
        ).strip().upper()

        if user_input == 'Y':
            if all:
                self._remove_directory(self.cache_dir)
                print('Cache cleared.')
            else:
                entity_root = get_model_cache_root(
                ) if single_model else get_dataset_cache_root()
                entity_directory = os.path.join(entity_root, id)
                temp_directory = os.path.join(entity_root,
                                              TEMPORARY_FOLDER_NAME, id)
                entity_removed = self._remove_directory(entity_directory)
                temp_removed = self._remove_directory(temp_directory)
                if (not entity_removed) and (not temp_removed):
                    if single_model:
                        print(
                            f'Cache for Model {id} not found. Nothing to do.')
                    else:
                        print(
                            f'Cache for Dataset {id} not found. Nothing to do.'
                        )
                else:
                    print('Cache cleared.')
        else:
            print('Operation aborted.')
            return

    def _remove_directory(self, path):
        if os.path.exists(path):
            try:
                if os.path.islink(path):
                    shutil.rmtree(os.readlink(path))
                    os.remove(path)
                    print(f'Cache and link for {path} removed.')
                else:
                    shutil.rmtree(path)
                    print(f'Cache folder {path} removed.')
                return True
            except Exception as e:
                print(f'An error occurred while clearing cache at {path}: {e}')
            return False
