from cmdbox.app import common, feature
from cmdbox.app.options import Options
from typing import Dict, Any, Tuple, Union, List
import argparse
import logging
import sys

class InstallMmcv(feature.UnsupportEdgeFeature):
    def get_mode(self) -> Union[str, List[str]]:
        """
        この機能のモードを返します

        Returns:
            Union[str, List[str]]: モード
        """
        return 'install'

    def get_cmd(self):
        """
        この機能のコマンドを返します

        Returns:
            str: コマンド
        """
        return 'mmcv'

    def get_option(self):
        """
        この機能のオプションを返します

        Returns:
            Dict[str, Any]: オプション
        """
        return dict(
            use_redis=self.USE_REDIS_FALSE, nouse_webmode=True, use_agent=False,
            description_ja="`mmcv` をインストールします。",
            description_en="Install `mmcv`.",
            choice=[
                dict(opt="install_use_gpu", type=Options.T_BOOL, default=False, required=False, multi=False, hide=False, choice=[True, False],
                     description_ja="GPUを使用するモジュール構成でインストールします。",
                     description_en="Install with a module configuration that uses the GPU."),
                dict(opt="output_json", short="o", type=Options.T_FILE, default=None, required=False, multi=False, hide=True, choice=None, fileio="out",
                     description_ja="処理結果jsonの保存先ファイルを指定。",
                     description_en="Specify the destination file for saving the processing result json.",
                     test_true={"win":None}),
                dict(opt="output_json_append", short="a", type=Options.T_BOOL, default=False, required=False, multi=False, hide=True, choice=[True, False],
                     description_ja="処理結果jsonファイルを追記保存します。",
                     description_en="Save the processing result json file by appending."),
                dict(opt="stdout_log", type=Options.T_BOOL, default=True, required=False, multi=False, hide=True, choice=[True, False],
                     description_ja="GUIモードでのみ使用可能です。コマンド実行時の標準出力をConsole logに出力します。",
                     description_en="Available only in GUI mode. Outputs standard output during command execution to Console log."),
                dict(opt="capture_stdout", type=Options.T_BOOL, default=True, required=False, multi=False, hide=True, choice=[True, False],
                     description_ja="GUIモードでのみ使用可能です。コマンド実行時の標準出力をキャプチャーし、実行結果画面に表示します。",
                     description_en="Available only in GUI mode. Captures standard output during command execution and displays it on the execution result screen."),
                dict(opt="capture_maxsize", type=Options.T_INT, default=self.DEFAULT_CAPTURE_MAXSIZE, required=False, multi=False, hide=True, choice=None,
                     description_ja="GUIモードでのみ使用可能です。コマンド実行時の標準出力の最大キャプチャーサイズを指定します。",
                     description_en="Available only in GUI mode. Specifies the maximum capture size of standard output when executing commands."),
            ]
        )

    def apprun(self, logger:logging.Logger, args:argparse.Namespace, tm:float, pf:List[Dict[str, float]]=[]) -> Tuple[int, Dict[str, Any], Any]:
        """
        この機能の実行を行います

        Args:
            logger (logging.Logger): ロガー
            args (argparse.Namespace): 引数
            tm (float): 実行開始時間
            pf (List[Dict[str, float]]): 呼出元のパフォーマンス情報

        Returns:
            Tuple[int, Dict[str, Any], Any]: 終了コード, 結果, オブジェクト
        """
        ret = self.mmcv(logger, install_use_gpu=args.install_use_gpu)
        common.print_format(ret, args.format, tm, args.output_json, args.output_json_append, pf=pf)

        if 'success' not in ret:
            return self.RESP_WARN, ret, None
        return self.RESP_SUCCESS, ret, None

    def mmcv(self, logger:logging.Logger, install_use_gpu:bool=False):
        msg = self._numpy(logger)
        if "success" not in msg: return msg
        if install_use_gpu:
            #returncode, _, _cmd = common.cmd('pip install mmcv==2.1.0 -f https://download.openmmlab.com/mmcv/dist/cu121/torch2.1/index.html', logger=self.logger, slise=-1)
            returncode, _, _cmd = common.cmd('pip install mmcv==2.2.0 -f https://download.openmmlab.com/mmcv/dist/cu121/torch2.4/index.html', logger=logger, slise=-1)
            #returncode, _, _cmd = common.cmd('mim install mmcv==2.2.0', logger=self.logger, slise=-1)
            #returncode, _, _cmd = common.cmd('pip install mmcv==2.1.0 -f https://download.openmmlab.com/mmcv/dist/cu118/torch2.1/index.html', logger=self.logger, slise=-1)
            if returncode != 0:
                logger.warning(f"Failed to install mmcv. cmd:{_cmd}")
                return {"error": f"Failed to install mmcv. cmd:{_cmd}"}
        else:
            returncode, _, _cmd = common.cmd('mim install mmcv==2.2.0', logger=logger, slise=-1)
            #returncode, _, _cmd = common.cmd('mim install mmcv==2.1.0', logger=logger, slise=-1)
            #returncode, _, _cmd = common.cmd('mim install mmcv>=2.0.0', logger=logger, slise=-1)
        if returncode != 0:
            logger.warning(f"Failed to install mmcv. cmd:{_cmd}")
            return {"error": f"Failed to install mmcv. cmd:{_cmd}"}
        return {"success": f"Success to install mmcv. cmd:{_cmd}"}

    def _openmin(self, logger:logging.Logger):
        returncode, _, _cmd = common.cmd('pip install --upgrade setuptools', logger=logger, slise=-1)
        if returncode != 0:
            logger.warning(f"Failed to install setuptools. cmd:{_cmd}")
            return {"error": f"Failed to install setuptools. cmd:{_cmd}"}
        returncode, _, _cmd = common.cmd('pip install openmim', logger=logger, slise=-1)
        if returncode != 0:
            logger.warning(f"Failed to install openmim. cmd:{_cmd}")
            return {"error": f"Failed to install openmim. cmd:{_cmd}"}
        return {"success": f"Success to install openmim. cmd:{_cmd}"}

    def _numpy(self, logger:logging.Logger):
        if sys.version_info[0] >= 3 and sys.version_info[1] >= 10:
            returncode, _, _cmd = common.cmd('pip install numpy==1.26.4', logger=logger, slise=-1)
        else:
            returncode, _, _cmd = common.cmd('pip install numpy==1.24.1', logger=logger, slise=-1)
        if returncode != 0:
            logger.warning(f"Failed to install numpy. cmd:{_cmd}")
            return {"error": f"Failed to install numpy. cmd:{_cmd}"}
        return {"success": f"Success to install numpy. cmd:{_cmd}"}

    def audited_by(self, logger:logging.Logger, args:argparse.Namespace) -> bool:
        """
        この機能が監査ログを記録する対象かどうかを返します

        Returns:
            logger (logging.Logger): ロガー
            args (argparse.Namespace): 引数
            bool: 監査ログを記録する場合はTrue
        """
        return False
