# Copyright (c) Alibaba, Inc. and its affiliates.
import os
import shutil
from argparse import ArgumentParser
from pathlib import Path

from modelscope.cli.base import CLICommand
from modelscope.hub.constants import TEMPORARY_FOLDER_NAME
from modelscope.hub.utils.utils import get_model_masked_directory


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 = os.getenv(
            'MODELSCOPE_CACHE',
            Path.home().joinpath('.cache', 'modelscope'))

    @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. For clear-cache, '
            '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. For clear-cache, '
            '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}, 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_directory = os.path.join(
                    self.cache_dir, 'hub' if single_model else 'datasets', id)
                temp_directory = os.path.join(
                    self.cache_dir, 'hub' if single_model else 'datasets',
                    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
