# -*- coding: utf-8 -*-
from pickle import NONE
from .base import BaseTool
from .base import PrintUtils,CmdTask,FileUtils,AptUtils,ChooseTask
from .base import osversion
from .base import run_tool_file
from .base import tr


class RosVersion:
    STATUS_EOL = 0
    STATUS_LTS = 1
    def __init__(self,name,version,status,deps=[]):
        self.name = name
        self.version = version
        self.status = status
        self.deps = deps


class RosVersions:
    ros_version = [
        # ubuntu 24
        RosVersion('jazzy',  'ROS2', RosVersion.STATUS_LTS, ['python3-colcon-common-extensions','python3-argcomplete','python3-rosdep']),
        # ubuntu 22 & 24
        RosVersion('rolling',  'ROS2', RosVersion.STATUS_LTS, ['python3-colcon-common-extensions','python3-argcomplete','python3-rosdep']),
        RosVersion('eloquent',  'ROS2', RosVersion.STATUS_EOL, ['python3-colcon-common-extensions','python3-argcomplete','python3-rosdep']),
        # ubuntu 22
        RosVersion('iron',  'ROS2', RosVersion.STATUS_LTS, ['python3-colcon-common-extensions','python3-argcomplete','python3-rosdep']),
        RosVersion('humble',  'ROS2', RosVersion.STATUS_LTS, ['python3-colcon-common-extensions','python3-argcomplete','python3-rosdep']),
        RosVersion('galactic',  'ROS2', RosVersion.STATUS_LTS, ['python3-colcon-common-extensions','python3-argcomplete','python3-rosdep']),
        # ubuntu 20
        RosVersion('foxy',  'ROS2', RosVersion.STATUS_LTS, ['python3-colcon-common-extensions','python3-argcomplete','python3-rosdep']),
        RosVersion('noetic',  'ROS1', RosVersion.STATUS_LTS, ['python3-catkin-tools','python3-rosdep']),
        # ubuntu 18
        RosVersion('melodic', 'ROS1', RosVersion.STATUS_LTS, ['python-catkin-tools','python-rosdep']),
        RosVersion('dashing',  'ROS2', RosVersion.STATUS_EOL, []),
        # ubuntu 16
        RosVersion('kinetic', 'ROS1', RosVersion.STATUS_EOL, ['python-catkin-tools','python-rosdep']),
        RosVersion('crystal',  'ROS2', RosVersion.STATUS_EOL, []),
        RosVersion('bouncy',  'ROS2', RosVersion.STATUS_EOL, []),
        RosVersion('ardent',  'ROS2', RosVersion.STATUS_EOL, []),
        RosVersion('lunar', 'ROS2', RosVersion.STATUS_EOL, []),
    ]

    @staticmethod
    def get_version_string(name):
        for version in RosVersions.ros_version:
            if version.name == name:
                return "{}({})".format(version.name,version.version)

    @staticmethod
    def get_version(name):
        for version in RosVersions.ros_version:
            if version.name == name:
                return version
       
    @staticmethod
    def install_depend(name):
        depends = RosVersions.get_version(name).deps
        for dep in depends:
            AptUtils.install_pkg(dep)


    @staticmethod
    def tip_test_command(name):
        version = RosVersions.get_version(name).version
        if version=="ROS1":
            PrintUtils.print_warn("小鱼,黄黄的提示:您安装的是ROS1,可以打开一个新的终端输入roscore测试!")
        elif version=="ROS2":
            PrintUtils.print_warn("小鱼:黄黄的提示:您安装的是ROS2,ROS2是没有roscore的,请打开新终端输入ros2测试!小鱼制作了ROS2课程,关注公众号《鱼香ROS》即可获取~")

    @staticmethod
    def get_desktop_version(name):
        version = RosVersions.get_version(name).version
        if version=="ROS1":
            return "ros-{}-desktop-full".format(name)
        elif version=="ROS2":
            return "ros-{}-desktop".format(name)


key_urls = [
    'https://gitee.com/ohhuo/rosdistro/raw/master/ros.asc',
    'https://raw.githubusercontent.com/ros/rosdistro/master/ros.asc',
]

ros_mirror_dic = {
    "tsinghua":{"ROS1":"http://mirrors.tuna.tsinghua.edu.cn/ros/ubuntu/","ROS2":"http://mirrors.tuna.tsinghua.edu.cn/ros2/ubuntu/"},
    "huawei":{"ROS1":"https://repo.huaweicloud.com/ros/ubuntu/","ROS2":"https://repo.huaweicloud.com/ros2/ubuntu/"},
    "packages.ros":{"ROS1":"http://packages.ros.org/ros/ubuntu/","ROS2":"http://packages.ros.org/ros2/ubuntu/"},
    "https.packages.ros":{"ROS1":"https://packages.ros.org/ros/ubuntu/","ROS2":"https://packages.ros.org/ros2/ubuntu/"},
    "repo-ros2":{"ROS2":"http://repo.ros2.org/ubuntu/"}
}


ros_dist_dic = {
    'artful':{"packages.ros"},
    'bionic':{"tsinghua","huawei","packages.ros","https.packages.ros"},
    'buster':{"packages.ros"},
    'cosmic':{"packages.ros"},
    'disco':{"packages.ros"},
    'eoan':{"packages.ros"},
    'focal':{"tsinghua","huawei","packages.ros","https.packages.ros"},
    'jessie':{"tsinghua","huawei","packages.ros","https.packages.ros"},
    'lucid':{"packages.ros"},
    'maverick':{"packages.ros"},
    'natty':{"packages.ros"},
    'oneiric':{"packages.ros"},
    'precise':{"packages.ros"},
    'quantal':{"packages.ros"},
    'raring':{"packages.ros"},
    'saucy':{"packages.ros"},
    'stretch':{"tsinghua","huawei","packages.ros","https.packages.ros"},
    'trusty':{"tsinghua","huawei","packages.ros","https.packages.ros"},
    'utopic':{"packages.ros"},
    'vivid':{"packages.ros"},
    'wheezy':{"packages.ros"},
    'wily':{"packages.ros"},
    'xenial':{"tsinghua","huawei","packages.ros","https.packages.ros"},
    'yakkety':{"packages.ros"},
    'zesty':{"packages.ros"},
}


ros2_dist_dic = {
    'bionic':{"tsinghua","huawei","packages.ros","https.packages.ros"},
    'bullseye':{"tsinghua","huawei","packages.ros","https.packages.ros"},
    'buster':{"packages.ros"},
    'cosmic':{"tsinghua","huawei","packages.ros","https.packages.ros"},
    'disco':{"tsinghua","huawei","packages.ros","https.packages.ros"},
    'eoan':{"tsinghua","huawei","packages.ros","https.packages.ros"},
    'focal':{"tsinghua","huawei","packages.ros","https.packages.ros"},
    'jessie':{"tsinghua","huawei"},
    'jammy':{"tsinghua","huawei","packages.ros","https.packages.ros"},
    'noble':{"tsinghua","huawei","packages.ros","https.packages.ros"},
    'stretch':{"tsinghua","huawei","packages.ros","https.packages.ros"},
    'trusty':{"tsinghua","huawei"},
    'xenial':{"tsinghua","huawei","packages.ros","https.packages.ros"},
}



class Tool(BaseTool):
    def __init__(self):
        self.name = "一键安装ROS和ROS2,支持树莓派Jetson"
        self.type = BaseTool.TYPE_INSTALL
        self.author = '小鱼'


    def get_mirror_by_code(self,code,arch='amd64',first_choose="tsinghua"):
        """
        获取镜像通过系统版本号
        """
        ros1_choose_queue = [first_choose,"tsinghua","huawei","packages.ros"]
        ros2_choose_queue = [first_choose,"tsinghua","huawei","packages.ros"]
        
        # armhf架构,优先使用官方源
        if arch=='armhf': ros2_choose_queue =["packages.ros","tsinghua","huawei"]

        mirror = []
        # 确认源里有对应的系统的,比如jammy
        if code in ros_dist_dic.keys():
            for item in ros1_choose_queue:
                if item in ros_dist_dic[code]:
                    mirror.append(ros_mirror_dic[item]['ROS1'])
                    break
         # 确认源里有对应的系统的,比如jammy
        if code in ros2_dist_dic.keys():
            for item in ros2_choose_queue:
                if item in ros2_dist_dic[code]:
                    mirror.append(ros_mirror_dic[item]['ROS2'])
                    break
        # if code in ['focal']:
        #     mirror.append(ros_mirror_dic['packages.ros']['ROS2'])
        return mirror


    def add_key(self):
        PrintUtils.print_success(tr.tr('============正在添加ROS源密钥================='))
        # check apt
        if not AptUtils.checkapt(): 
            pass
        # install dep
        AptUtils.install_pkg('curl')
        AptUtils.install_pkg('gnupg2')

        # add key
        PrintUtils.print_success(tr.tr('正在挑选最快的密钥服务:{}').format(key_urls))
        key_url = AptUtils.get_fast_url(key_urls)
        if not key_url: 
            PrintUtils.print_error(tr.tr("获取密钥失败"))
            return
        key_url = key_url[0]
        PrintUtils.print_success(tr.tr('已自动选择最快密钥服务:{}').format(key_url))

        cmd_result = CmdTask("curl -s {} | sudo apt-key add -".format(key_url)).run()
        if cmd_result[0]!=0: 
            cmd_result = CmdTask("curl -s {} | sudo apt-key add -".format(key_url)).run()
            
        if cmd_result[0]!=0:
            PrintUtils.print_info(tr.tr("导入密钥失败,开始更换导入方式并二次尝试..."))
            cmd_result = CmdTask("sudo apt-key adv --keyserver keyserver.ubuntu.com --recv-keys F42ED6FBAB17C654",10).run()

        # 针对trusted.gpg.d问题解决方案
        if FileUtils.check_result(cmd_result,['trusted.gpg.d']):
            cmd_result = CmdTask("curl -s {} | sudo gpg --no-default-keyring --keyring gnupg-ring:/etc/apt/trusted.gpg.d/ros.gpg --import".format(key_url)).run()
            cmd_result = CmdTask("sudo chmod 644 /etc/apt/trusted.gpg.d/ros.gpg",10).run()

        return cmd_result


    def check_sys_source(self):
        # 更换系统源
        dic = {1:"更换系统源再继续安装",2:"不更换继续安装"}
        PrintUtils.print_warn("=========接下来这一步很很很很重要,如果不知道怎么选请选择1========")
        code,result = ChooseTask(dic, "新手或首次安装一定要一定要一定要换源并清理三方源,换源!!!系统默认国外源容易失败!!").run()
        if code==1: 
            tool = run_tool_file('tools.tool_config_system_source',authorun=False)
            tool.change_sys_source()

    def get_all_instsll_ros_pkgs(self):
        AptUtils.checkapt()
        dic_base = AptUtils.search_package('ros-base','ros-[A-Za-z]+-ros-base',"ros-","-base")
        if dic_base== None: return None
        ros_name = {}
        for a in dic_base.keys(): 
            ros_name[RosVersions.get_version_string(a)] = a
        if len(ros_name) == 0:
            return None
        return ros_name

    def add_source(self):
        """
        检查并添加ROS系统源
        """
        arch = AptUtils.getArch()
        if arch==None: return False

        #add source 1
        mirrors = self.get_mirror_by_code(osversion.get_codename(),arch=arch)
        PrintUtils.print_info("根据您的系统,为您推荐安装源为{}".format(mirrors))
        source_data = ''
        for mirror in mirrors:
            source_data += 'deb [arch={}]  {} {} main\n'.format(arch,mirror,osversion.get_codename())
        FileUtils.delete('/etc/apt/sources.list.d/ros-fish.list')
        FileUtils.new('/etc/apt/sources.list.d/',"ros-fish.list",source_data)

        ros_pkg = self.get_all_instsll_ros_pkgs()
        if ros_pkg and len(ros_pkg)>1:
            PrintUtils.print_success("恭喜,成功添加ROS源,接下来可以使用apt安装ROS或者使用[1]一键安装ROS安装!") 
            return
        
        #add source2 
        PrintUtils.print_warn("换源后更新失败,第二次开始切换源,尝试更换ROS2源为华为源!") 
        mirrors = self.get_mirror_by_code(osversion.get_codename(),arch=arch,first_choose="huawei")
        PrintUtils.print_info("根据您的系统,为您推荐安装源为{}".format(mirrors))
        source_data = ''
        for mirror in mirrors:
            source_data += 'deb [arch={}]  {} {} main\n'.format(arch,mirror,osversion.get_codename())
        FileUtils.delete('/etc/apt/sources.list.d/ros-fish.list')
        FileUtils.new('/etc/apt/sources.list.d/',"ros-fish.list",source_data)
        ros_pkg = self.get_all_instsll_ros_pkgs()
        if ros_pkg and len(ros_pkg)>1:
            PrintUtils.print_success("恭喜,成功添加ROS源,接下来可以使用apt安装ROS或者使用[1]一键安装ROS安装!") 
            return


        PrintUtils.print_warn("换源后更新失败,第三次开始切换源,尝试使用https-ROS官方源~!") 
        mirrors = self.get_mirror_by_code(osversion.get_codename(),arch=arch,first_choose="https.packages.ros")
        PrintUtils.print_info("根据您的系统,为您推荐安装源为{}".format(mirrors))
        source_data = ''
        for mirror in mirrors:
            source_data += 'deb [arch={}]  {} {} main\n'.format(arch,mirror,osversion.get_codename())
        FileUtils.delete('/etc/apt/sources.list.d/ros-fish.list')
        FileUtils.new('/etc/apt/sources.list.d/',"ros-fish.list",source_data)
        ros_pkg = self.get_all_instsll_ros_pkgs()
        if ros_pkg and len(ros_pkg)>1:
            PrintUtils.print_success("恭喜,成功添加ROS源,接下来可以使用apt安装ROS或者使用[1]一键安装ROS安装!") 
            return

        #add source2 
        PrintUtils.print_warn("换源后更新失败,第四次开始切换源,尝试更换ROS源为http-ROS官方源!") 
        mirrors = self.get_mirror_by_code(osversion.get_codename(),arch=arch,first_choose="packages.ros")
        PrintUtils.print_info("根据您的系统,为您推荐安装源为{}".format(mirrors))
        source_data = ''
        for mirror in mirrors:
            source_data += 'deb [arch={}]  {} {} main\n'.format(arch,mirror,osversion.get_codename())
        FileUtils.delete('/etc/apt/sources.list.d/ros-fish.list')
        FileUtils.new('/etc/apt/sources.list.d/',"ros-fish.list",source_data)
        ros_pkg = self.get_all_instsll_ros_pkgs()
        if ros_pkg and len(ros_pkg)>1:
            PrintUtils.print_success("恭喜,成功添加ROS源,接下来可以使用apt安装ROS或者使用[1]一键安装ROS安装!") 
            return

        # echo >>/etc/apt/apt.conf.d/99verify-peer.conf "Acquire { https::Verify-Peer false }"
        if  not AptUtils.checkapt(): PrintUtils.print_error("四次换源后都失败了,请及时联系小鱼获取解决方案并处理!") 


    def support_install(self):
        # check support
        if (osversion.get_codename() not in ros_dist_dic.keys()) and (osversion.get_codename() not in ros2_dist_dic.keys()):
            PrintUtils.print_error("小鱼:检测当前系统{}{}:{} 暂不支持一键安装ROS,请关注公众号《鱼香ROS》获取帮助.".format(osversion.get_name(), osversion.get_version(),osversion.get_codename()))
            return False
        PrintUtils.print_success("小鱼:检测当前系统{}{}:{} 支持一键安装ROS".format(osversion.get_name(), osversion.get_version(),osversion.get_codename()))
        return True

    def install_success(self,name):
        """
        检查某个版本的ROS是否安装成功
        """
        result = CmdTask("ls /opt/ros/{}/setup.bash".format(name), 0).run()
        if str(result[1]).find('setup.bash') >= 1:
            return True
        return False

    

    def choose_and_install_ros(self):
        # search ros packages
        dic_base = AptUtils.search_package('ros-base','ros-[A-Za-z]+-ros-base',"ros-","-base")
        if dic_base== None: return False

        ros_name = {}
        for a in dic_base.keys(): 
            ros_name[RosVersions.get_version_string(a)] = a

        code,rosname = ChooseTask(ros_name.keys(),"请选择你要安装的ROS版本名称(请注意ROS1和ROS2区别):",True).run()
        if code==0: 
            PrintUtils.print_error("你选择退出")
            PrintUtils.print_delay('是因为没有自己想要的ROS版本吗?ROS版本和操作系统版本是有对应关系的哦,所以可能是你的系统版本{}不对!具体请查看:https://fishros.org.cn/forum/topic/96'.format(str(str(osversion.get_name())+str(osversion.get_version()))))
            return
        version_dic = {1:rosname+"桌面版",2:rosname+"基础版(小)"}
        code,name = ChooseTask(version_dic,"请选择安装的具体版本(如果不知道怎么选,请选1桌面版):",False).run()
        
        if code==0: 
            print("你选择退出。。。。")
            return
        
        install_tool = 'aptitude'
        install_tool_apt = 'apt'
        if osversion.get_version() == "16.04":
            install_tool = 'apt'

        install_version = ros_name[rosname]

        if install_tool=='aptitude':
            AptUtils.install_pkg('aptitude')

        # ======================================================基础版本==============================================================
        if code==2:
            # 第一次尝试
            cmd_result = CmdTask("sudo {} install  {} -y".format(install_tool_apt,dic_base[install_version]),300,os_command=True).run()
            cmd_result = CmdTask("sudo {} install  {} -y".format(install_tool_apt,dic_base[install_version]),300,os_command=False).run()
            if FileUtils.check_result(cmd_result,['未满足的依赖关系','unmet dependencies','but it is not installable']):
                # 尝试使用aptitude解决依赖问题
                PrintUtils.print_warn("============================================================")
                PrintUtils.print_delay("请注意我,检测你在安装过程中出现依赖问题,请在稍后输入n,再选择y,即可解决")
                import time
                input("确认了解情况,请输入回车继续安装")
                cmd_result = CmdTask("sudo {} install   {} ".format(install_tool,dic_base[install_version]),300,os_command=True).run()
                cmd_result = CmdTask("sudo {} install   {} -y".format(install_tool,dic_base[install_version]),300,os_command=False).run()
        
        # ======================================================桌面版本==============================================================
        elif code==1:
            cmd_result = CmdTask("sudo {} install   {} -y".format(install_tool_apt,RosVersions.get_desktop_version(install_version)),300,os_command=True).run()
            cmd_result = CmdTask("sudo {} install   {} -y".format(install_tool_apt,RosVersions.get_desktop_version(install_version)),300,os_command=False).run()
            if FileUtils.check_result(cmd_result,['未满足的依赖关系','unmet dependencies','but it is not installable']):
                # 尝试使用aptitude解决依赖问题
                PrintUtils.print_warn("============================================================")
                PrintUtils.print_delay("请注意我,检测你在安装过程中出现依赖问题,请在稍后输入n,再选择y,即可解决(若无法解决,清在稍后手动运行命令: sudo aptitude install {})".format(RosVersions.get_desktop_version(install_version)))
                import time
                input("确认了解情况,请输入回车继续安装")
                cmd_result = CmdTask("sudo {} install   {}".format(install_tool,RosVersions.get_desktop_version(install_version)),300,os_command=True).run()
                cmd_result = CmdTask("sudo {} install   {} -y".format(install_tool,RosVersions.get_desktop_version(install_version)),300,os_command=False).run()

        # apt broken error
        if cmd_result[0]!=0:
            if FileUtils.check_result(cmd_result,['--fix-broken install']):
                CmdTask("sudo apt --fix-broken install -y").run()
                if code==2: cmd_result = CmdTask("sudo {} install   {} -y".formatinstall_tool,(dic_base[rosname]),300,os_command=False).run()
                elif code==1: cmd_result = CmdTask("sudo {} install   {} -y".format(install_tool,rosname),300,os_command=False).run()

        # 安装额外的依赖
        RosVersions.install_depend(install_version)

        return install_version


    def config_env_and_tip(self,version_name):
        """
        配置系统源
        """
        if self.install_success(version_name):
            run_tool_file('tools.tool_config_rosenv')
            PrintUtils.print_success("恭喜你,安装成功了,再附赠你机器人学习宝藏网站:鱼香社区:https://fishros.org.cn/forum")
        else: PrintUtils.print_error("安装失败了,请打开鱼香社区:https://fishros.org.cn/forum 在一键安装专区反馈问题...")


    def install_ros(self):
        PrintUtils.print_delay('欢迎使用ROS开箱子工具,本工具由[鱼香ROS]小鱼贡献..')
        if not self.support_install(): return False

        self.check_sys_source()
        self.add_key()
        self.add_source()

        ros_version = self.choose_and_install_ros()
        if not ros_version:
            return
        self.config_env_and_tip(ros_version)
        if self.install_success(ros_version):
            RosVersions.tip_test_command(ros_version)


    def run(self):
        self.install_ros()