# coding: utf-8
# -------------------------------------------------------------------
# YakPanel
# -------------------------------------------------------------------
# Copyright (c) 2015-2099 YakPanel(www.yakpanel.com) All rights reserved.
# -------------------------------------------------------------------
# Author: zouhw <zhw@yakpanel.com>
# -------------------------------------------------------------------

# ------------------------------
# Docker模型
# ------------------------------
import json

import public
from btdockerModelV2 import dk_public as dp
from btdockerModelV2.dockerBase import dockerBase
from public.validate import Param

class main(dockerBase):

    def docker_client(self, url):
        return dp.docker_client(url)

    def add(self, args):
        """
        添加仓库
        :param registry 仓库URL docker.io
        :param name
        :parma username
        :parma password
        :param namespace 仓库命名空间
        :param remark 备注
        :param args:
        :return:
        """
        # {"registry": "docker.io", "name": "wzznb", "username": "akaishuichi", "password": "xiuyi999..",
        #  "namespace": "akaishuichi", "remark": "wzz_docker_io"}

        # 校验参数
        try:
            args.validate([
                Param('name').Require().String(),
                Param('username').Require().String(),
                Param('password').Require().String(),
                Param('namespace').Require().String(),
                Param('remark').String(),

            ], [
                public.validate.trim_filter(),
            ])
        except Exception as ex:
            public.print_log("error info: {}".format(ex))
            return public.return_message(-1, 0, str(ex))
        # 验证登录
        if not args.registry:
            args.registry = "docker.io"
        res = self.login(self._url, args.registry, args.username, args.password)

        if not res['status']:
            return public.return_message(-1, 0, res['msg'])
        r_list = self.registry_list(args)
        if len(r_list) > 0:
            for r in r_list:
                if "reg_name" in r:
                    if r['reg_name'] == args.name and r["reg_url"] == args.registry and r['username'] == args.username:
                        return public.return_message(-1, 0, public.lang("Repository information already exists!"))

                if r['name'] == args.name and r["reg_url"] == args.registry and r['username'] == args.username:
                    return public.return_message(-1, 0, public.lang("Repository information already exists!"))
        pdata = {
            "reg_name": args.name,
            "url": args.registry,
            "namespace": args.namespace,
            "username": public.aes_encrypt(args.username, self.aes_key),
            "password": public.aes_encrypt(args.password, self.aes_key),
            "remark": public.xsssec(args.remark)
        }
        aa = dp.sql("registry").insert(pdata)

        dp.write_log("Added repository [{}] [{}] success!".format(args.name, args.registry))
        return public.return_message(0, 0, public.lang("successfully added!"))

    def edit(self, args):
        """
        编辑仓库
        :param registry 仓库URL docker.io
        :param id 仓库id
        :parma username
        :parma password
        :param namespace
        :param remark
        :param args:
        :return:
        """

        # 校验参数
        try:
            args.validate([
                Param('id').Require().Integer(),
                Param('username').Require().String(),
                Param('password').Require().String(),
                Param('namespace').Require().String(),
                Param('remark').String(),

            ], [
                public.validate.trim_filter(),
            ])
        except Exception as ex:
            public.print_log("error info: {}".format(ex))
            return public.return_message(-1, 0, str(ex))

        # 验证登录
        # if str(args.id) == "1":
        #     return public.return_message(-1, 0, public.lang("[Official Docker repository] Not editable!"))
        if not args.registry:
            args.registry = "docker.io"

        # 2023/12/13 上午 11:40 处理加密的编辑
        try:
            is_encrypt = False
            res = self.login(self._url, args.registry, args.username, args.password)
            if not res['status']:
                res = self.login(
                    self._url,
                    args.registry,
                    public.aes_decrypt(args.username, self.aes_key),
                    public.aes_decrypt(args.password, self.aes_key)
                )
                if not res['status']:
                    return public.return_message(-1, 0, res['msg'])
                is_encrypt = True
        except Exception as e:
            if "binascii.Error: Incorrect padding" in str(e):
                return public.return_message(-1, 0, public.lang("Editing failed! Reason: Account password decryption failed! Please delete the repository and add it again"))
            return public.return_message(-1, 0, public.lang("Editing failed! Reason:{}", e))

        res = dp.sql("registry").where("id=?", (args.id,)).find()
        if not res:
            return public.return_message(-1, 0, public.lang("This repository could not be found"))
        pdata = {
            "reg_name": args.name,
            "url": args.registry,
            "username": public.aes_encrypt(args.username, self.aes_key) if is_encrypt is False else args.username,
            "password": public.aes_encrypt(args.password, self.aes_key) if is_encrypt is False else args.password,
            "namespace": args.namespace,
            "remark": args.remark
        }
        dp.sql("registry").where("id=?", (args.id,)).update(pdata)
        dp.write_log("Edit repository [{}][{}] Success!".format(args.name, args.registry))
        return public.return_message(0, 0, public.lang("Edit success!"))

    def remove(self, args):
        """
        删除某个仓库
        :param id
        :param rags:
        :return:
        """
        # 校验参数
        try:
            args.validate([
                Param('id').Require().Integer(),
            ], [
                public.validate.trim_filter(),
            ])
        except Exception as ex:
            public.print_log("error info: {}".format(ex))
            return public.return_message(-1, 0, str(ex))

        # if str(args.id) == "1":
        #     return public.return_message(-1, 0, public.lang("[Official Docker repository] can not be removed!"))

        data = dp.sql("registry").where("id=?", (args.id)).find()

        if len(data) < 1:
            return public.return_message(0, 0, public.lang("Delete failed,The repository id may not exist!"))

        dp.sql("registry").where("id=?", (args.id,)).delete()

        dp.write_log("Delete repository [{}][{}] Success!".format(data['name'], data['url']))
        return public.return_message(0, 0, public.lang("Successfully deleted!"))
    def registry_list(self, get):
        """
        获取仓库列表
        :return:
        """
        self.check_table_dk_registry()
        db_obj = dp.sql("registry")
        # 2024/1/3 下午 6:00 检测数据库是否存在并且表健康
        search_result = db_obj.where('id=? or name=?', (1, "Docker public repository")).select()

        # if db_obj.ERR_INFO:
        #     return []


        if len(search_result) == 0:
            dp.sql("registry").insert({
                "name": "Docker public repository",
                "url": "docker.io",
                "username": "",
                "password": "",
                "namespace": "",
                "remark": "Docker public repository"
            })
        if "error: no such table: registry" in search_result or len(search_result) == 0:
            # public.ExecShell("mv -f /www/server/panel/data/docker.db /www/server/panel/data/db/docker.db")
            public.ExecShell("mv -f /www/server/panel/data/db/docker.db /www/server/panel/data/docker.db")
            dp.check_db()

        res = dp.sql("registry").select()
        if not isinstance(res, list):
            res = []

        for r in res:
            if "reg_name" not in r: continue
            if r["name"] == "" or not r["name"] or r["name"] is None:
                r["name"] = r["reg_name"]

        return res
    # 改返回
    def registry_listV2(self, get):
        """
        获取仓库列表
        :return:
        """
        res = self.registry_list(get)
        return public.return_message(0, 0,  res)
    # 2024/5/24 下午6:09 设置备注
    def set_remark(self, get):
        '''
            @name 设置备注
            @param "data":{"id":"仓库ID","remark":"备注"}
            @return dict{"status":True/False,"msg":"提示信息"}
        '''
        try:
            get.remark = get.get("remark/s", "")
            if get.remark != "":
                get.remark = public.xssencode2(get.remark)

            dp.sql("registry").where("id=?", (get.id,)).setField("remark", get.remark)
            return public.return_message(0, 0,  public.lang("Setup Successful!"))
        except Exception as e:
            return public.return_message(-1, 0, public.lang("Setup failed!{}",str(e)))

    def get_com_registry(self, get):
        """
        获取常用仓库列表
        @param get:
        @return:
        """
        com_registry_file = "{}/class/btdockerModelV2/config/com_registry.json".format(public.get_panel_path())
        try:
            com_registry = json.loads(public.readFile(com_registry_file))
        except:
            com_registry = {
                "docker.io": "Docker public repository",
                "swr.cn-north-4.myhuaweicloud.com": "Huawei Cloud mirror station",
                "ccr.ccs.tencentyun.com": "Tencent cloud mirror station",
                "registry.cn-hangzhou.aliyuncs.com": "Alibaba Cloud Mirror Station (Hangzhou)"
            }

        return public.return_message(0, 0, com_registry)
    # todo  检查字段新增reg_name
    def registry_info(self, get):
        '''
            @name 获取指定仓库的信息
            @author wzz <2024/5/24 下午3:16>
            @param "data":{"参数名":""} <数据类型> 参数描述
            @return dict{"status":True/False,"msg":"提示信息"}
        '''
        registry_info = dp.sql("registry").where("reg_name=? and url=?", (get.name, get.url)).find()
        if not registry_info:
            registry_info = dp.sql("registry").where("name=? and url=?", (get.name, get.url)).find()

        return registry_info

    def login(self, url, registry, username, password):
        """
        仓库登录测试
        :param args:
        :return:
        """

        try:
            res = self.docker_client(url).login(
                registry=registry,
                username=username,
                password=password,
                reauth=False
            )

            return public.returnMsg(True, str(res))
        except:
            error_info = public.get_error_info()
            return public.returnMsg(False, public.lang("Login test failed! Reason: {}", error_info))
        # except docker.errors.APIError as e:
        #     if "authentication required" in str(e):
        #         return public.returnMsg(False, public.lang("Login test failed! Reason: May be account password error, please check!"))
        #     if "unauthorized: incorrect username or password" in str(e):
        #         return public.returnMsg(False, public.lang("Login test failed! Reason: May be account password error, please check!"))
        #     return public.returnMsg(False, public.lang("Login test failed! Reason: {}", e))


    def check_table_dk_registry(self):
        '''
            @name 检查表registry 字段 reg_name  remark是否存在
            @return dict{"status":True/False,"msg":"提示信息"}
        '''

        # if public.M('sqlite_master').where('type=? AND name=?', ('table', 'docker_log_split')).count():
        #     create_table_str = public.M('sqlite_master').where('type=? AND name=?', ('table', 'docker_log_split')).getField('sql')
        #
        # if dp.sql('sqlite_master').where('type=? AND name=?', ('table', 'docker_log_split')).count():
        #     create_table_str = dp.sql('sqlite_master').where('type=? AND name=?', ('table', 'docker_log_split')).getField('sql')


        create_table_str = dp.sql('sqlite_master').where('type=? AND name=?', ('table', 'registry')).getField('sql')
        if create_table_str and 'reg_name' not in create_table_str:
            dp.sql('registry').execute('ALTER TABLE `registry` ADD COLUMN `reg_name` VARCHAR default "";')

        if create_table_str and 'remark' not in create_table_str:
            dp.sql('registry').execute('ALTER TABLE `registry` ADD COLUMN `remark` VARCHAR default "";')