import xbmcgui
import xbmcvfs
import xbmc
import base64
import urllib.request
import urllib.error
import ssl
import os
import hashlib
import time
import sqlite3
import shutil
import json

def decode_base64_str(encoded_str):
    if not encoded_str:
        return None
    try:
        encoded_str = encoded_str.replace('-', '+').replace('_', '/')
        padding = 4 - len(encoded_str) % 4
        if padding != 4:
            encoded_str += '=' * padding
        decoded_bytes = base64.b64decode(encoded_str, validate=True)
        decoded_str = decoded_bytes.decode('utf-8', errors='strict').strip()
        return decoded_str
    except base64.binascii.Error as e:
        xbmc.log(f"Base64格式错误：{encoded_str} | 错误：{str(e)}", level=xbmc.LOGERROR)
        return None
    except UnicodeDecodeError as e:
        xbmc.log(f"Base64解码后非UTF-8字符：{encoded_str} | 错误：{str(e)}", level=xbmc.LOGERROR)
        return None
    except Exception as e:
        xbmc.log(f"Base64解码失败：{encoded_str} | 错误：{str(e)}", level=xbmc.LOGERROR)
        return None

def get_ssl_context():
    try:
        ctx = ssl.create_default_context()
        ctx.check_hostname = False
        ctx.verify_mode = ssl.CERT_NONE
        return ctx
    except Exception as e:
        xbmc.log(f"创建SSL上下文失败：{str(e)}", level=xbmc.LOGERROR)
        return None

def build_gitee_api_url():
    try:
        token_part1_enc = 'NmVlYjAzZjc2'
        token_part2_enc = 'ZDBhOWM4OTE1OTEzMzM5ZDk4NjQ5NmQ='
        
        token_part1 = decode_base64_str(token_part1_enc)
        token_part2 = decode_base64_str(token_part2_enc)
        if not token_part1 or not token_part2:
            xbmc.log("Token分段解码失败", level=xbmc.LOGERROR)
            return None, None
        
        token = token_part1 + token_part2
        if not token:
            xbmc.log("Token拼接后为空", level=xbmc.LOGERROR)
            return None, None
        
        db_api_base_enc = 'aHR0cHM6Ly9naXRlZS5jb20vYXBpL3Y1L3JlcG9zL2NlLWZhbnMvTWluc2stc2tpbmF1dGgvY29udGVudHMvbWluc2stYXV0aC9NeVZpZGVvcy5kYg=='
        script_api_base_enc = 'aHR0cHM6Ly9naXRlZS5jb20vYXBpL3Y1L3JlcG9zL2NlLWZhbnMvTWluc2stc2tpbmF1dGgvY29udGVudHMvbWluc2stYXV0aC9yZWNvcmR1cGRhdGUucHk='
        
        db_api_base = decode_base64_str(db_api_base_enc)
        script_api_base = decode_base64_str(script_api_base_enc)
        if not db_api_base or not script_api_base:
            xbmc.log("API基础地址解码失败", level=xbmc.LOGERROR)
            return None, None
        
        separator_db = '&' if '?' in db_api_base else '?'
        db_api_url = f"{db_api_base}{separator_db}access_token={token}"
        
        separator_script = '&' if '?' in script_api_base else '?'
        script_api_url = f"{script_api_base}{separator_script}access_token={token}"
        
        return db_api_url, script_api_url
    except Exception as e:
        xbmc.log(f"构建API URL失败：{str(e)}", level=xbmc.LOGERROR)
        return None, None

def verify_card_key(input_key):
    target_hash_enc = 'MDY2MTQ4MWZlODhlNDliMTExYTMyN2NmOTlkZTJmMmE='
    target_hash = decode_base64_str(target_hash_enc)
    if not target_hash:
        return False
    input_hash = hashlib.md5(input_key.encode('utf-8')).hexdigest()
    return input_hash == target_hash

def get_decrypted_content(encoded_url_parts):
    try:
        domain = decode_base64_str(encoded_url_parts[0])
        path = decode_base64_str(encoded_url_parts[1])
        file = decode_base64_str(encoded_url_parts[2])
        if not all([domain, path, file]):
            return None
        url = f"https://{domain}{path}{file}"
        ctx = get_ssl_context()
        response = urllib.request.urlopen(url, context=ctx, timeout=20)
        encoded_content = response.read().decode('utf-8').strip()
        decoded_content = base64.b64decode(encoded_content).decode('utf-8')
        return decoded_content
    except Exception as e:
        xbmc.log(f"获取解密内容失败：{str(e)}", level=xbmc.LOGERROR)
        return None

def download_file(encoded_url_parts, encoded_save_path):
    try:
        domain = decode_base64_str(encoded_url_parts[0])
        path = decode_base64_str(encoded_url_parts[1])
        file = decode_base64_str(encoded_url_parts[2])
        if not all([domain, path, file]):
            return False
        url = f"https://{domain}{path}{file}"
        
        save_path = decode_base64_str(encoded_save_path)
        if not save_path:
            return False
        save_path = xbmcvfs.translatePath(save_path)
        
        # 确保目录存在
        dir_path = os.path.dirname(save_path)
        if not xbmcvfs.exists(dir_path):
            xbmcvfs.mkdirs(dir_path)
        
        ctx = get_ssl_context()
        response = urllib.request.urlopen(url, context=ctx, timeout=20)
        with open(save_path, 'wb') as f:
            f.write(response.read())
        return True
    except Exception as e:
        xbmc.log(f"下载文件失败：{str(e)}", level=xbmc.LOGERROR)
        return False

def execute_script(encoded_script_path):
    try:
        script_path = decode_base64_str(encoded_script_path)
        if not script_path:
            return False
        command = f'RunScript({script_path})'
        xbmc.executebuiltin(command)
        return True
    except Exception as e:
        xbmc.log(f"执行脚本失败：{str(e)}", level=xbmc.LOGERROR)
        return False

def download_file_with_gitee_api(api_url, save_path, overwrite=True):
    if not api_url:
        xbmc.log("API URL为空，无法下载", level=xbmc.LOGERROR)
        xbmcgui.Dialog().ok('错误', 'API地址为空，无法访问Gitee！')
        return False
    
    try:
        headers = {
            'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36',
            'Accept': 'application/json',
            'Accept-Language': 'zh-CN,zh;q=0.9,en;q=0.8',
            'Connection': 'keep-alive'
        }
        req = urllib.request.Request(api_url, headers=headers)
        ctx = get_ssl_context()
        response = urllib.request.urlopen(req, context=ctx, timeout=20)
        
        json_data = json.loads(response.read().decode('utf-8'))
        if 'content' not in json_data:
            xbmc.log(f"Gitee返回数据异常：{json.dumps(json_data)}", level=xbmc.LOGERROR)
            return False
        
        file_content = base64.b64decode(json_data['content'].encode('utf-8').replace(b'\n', b''))
        
        # 转换特殊路径并确保目录存在
        translated_path = xbmcvfs.translatePath(save_path) if 'special://' in save_path else save_path
        
        # 获取目录路径并创建目录
        dir_path = os.path.dirname(translated_path)
        if dir_path and not xbmcvfs.exists(dir_path):
            xbmcvfs.mkdirs(dir_path)
        
        # 写入文件
        with open(translated_path, 'wb') as f:
            f.write(file_content)
        
        return True
    except urllib.error.HTTPError as e:
        xbmc.log(f"HTTP错误：{e.code} | 原因：{e.reason} | URL：{api_url}", level=xbmc.LOGERROR)
        if e.code == 401:
            xbmcgui.Dialog().ok('错误', 'Token无效/过期或API地址错误，无法访问Gitee API！')
        elif e.code == 404:
            xbmcgui.Dialog().ok('错误', 'Gitee上的文件不存在，请检查路径！')
        elif e.code == 403:
            xbmcgui.Dialog().ok('错误', '无权限访问该Gitee仓库！')
        return False
    except urllib.error.URLError as e:
        xbmc.log(f"网络连接错误：{str(e.reason)} | URL：{api_url}", level=xbmc.LOGERROR)
        xbmcgui.Dialog().ok('错误', f'网络连接失败：{str(e.reason)}\n请检查：\n1. 网络是否正常\n2. CoreELEC是否能访问外网\n3. Gitee域名是否被屏蔽')
        return False
    except Exception as e:
        xbmc.log(f"下载失败：{str(e)} | URL：{api_url}", level=xbmc.LOGERROR)
        return False

def is_coreelec_system():
    coreelec_path_enc = 'L3N0b3JhZ2UvLmNvbmZpZy9zeXN0ZW0uZA=='
    coreelec_path = decode_base64_str(coreelec_path_enc)
    if not coreelec_path:
        coreelec_path = '/storage/.config/system.d'
    if xbmcvfs.exists(coreelec_path):
        return True
    os_name = xbmc.getInfoLabel('System.OSName').lower()
    return 'coreelec' in os_name

def check_and_create_database(db_path):
    """检查并确保数据库文件存在且可访问"""
    try:
        # 转换路径
        full_path = xbmcvfs.translatePath(db_path) if 'special://' in db_path else db_path
        
        # 检查目录是否存在，如果不存在则创建
        dir_path = os.path.dirname(full_path)
        if dir_path and not xbmcvfs.exists(dir_path):
            xbmcvfs.mkdirs(dir_path)
            xbmc.log(f"创建数据库目录: {dir_path}", level=xbmc.LOGINFO)
        
        # 检查文件是否存在
        if not xbmcvfs.exists(full_path):
            xbmc.log(f"数据库文件不存在，将尝试创建: {full_path}", level=xbmc.LOGINFO)
            # 创建一个空的数据库文件
            conn = sqlite3.connect(full_path)
            # 创建基本表结构
            cursor = conn.cursor()
            cursor.execute("""
                CREATE TABLE IF NOT EXISTS ce (
                    c1 TEXT,
                    c2 TEXT,
                    c3 TEXT
                )
            """)
            conn.commit()
            conn.close()
            xbmc.log(f"已创建新的数据库文件: {full_path}", level=xbmc.LOGINFO)
        
        # 测试能否打开数据库
        conn = sqlite3.connect(full_path)
        conn.close()
        xbmc.log(f"数据库文件验证成功: {full_path}", level=xbmc.LOGINFO)
        return True
    except Exception as e:
        xbmc.log(f"数据库文件检查失败: {str(e)} | 路径: {db_path}", level=xbmc.LOGERROR)
        return False

def query_db(db_path, qq_encoded):
    try:
        # 检查并确保数据库文件可用
        full_path = xbmcvfs.translatePath(db_path) if 'special://' in db_path else db_path
        if not check_and_create_database(db_path):
            xbmc.log(f"数据库文件不可用: {db_path}", level=xbmc.LOGERROR)
            return None
        
        # 尝试连接数据库
        conn = sqlite3.connect(full_path)
        cursor = conn.cursor()
        
        # 确保表存在
        cursor.execute("""
            CREATE TABLE IF NOT EXISTS ce (
                c1 TEXT,
                c2 TEXT,
                c3 TEXT
            )
        """)
        
        cursor.execute("SELECT c3 FROM ce WHERE c2 = ?", (qq_encoded,))
        result = cursor.fetchone()
        conn.close()
        return result[0] if result else None
    except sqlite3.OperationalError as e:
        xbmc.log(f"SQLite操作错误：{str(e)} | 路径：{db_path}", level=xbmc.LOGERROR)
        return None
    except Exception as e:
        xbmc.log(f"数据库查询失败：{str(e)} | 路径：{db_path}", level=xbmc.LOGERROR)
        return None

def update_idkey_file(qq_num, auth_date):
    try:
        idkey_path_enc = 'c3BlY2lhbDovL3VzZXJkYXRhL2FkZG9uX2RhdGEvc2tpbi5jb25mbHVlbmNlLm1pbnNrL2lka2V5'
        idkey_path = decode_base64_str(idkey_path_enc)
        if not idkey_path:
            idkey_path = 'special://userdata/addon_data/skin.confluence.minsk/idkey'
        idkey_path = xbmcvfs.translatePath(idkey_path)
        
        # 确保目录存在
        dir_path = os.path.dirname(idkey_path)
        if not xbmcvfs.exists(dir_path):
            xbmcvfs.mkdirs(dir_path)
            
        with open(idkey_path, 'w', encoding='utf-8') as f:
            f.write(f"{qq_num},{auth_date}")
        return True
    except Exception as e:
        xbmc.log(f"保存授权信息失败：{str(e)}", level=xbmc.LOGERROR)
        xbmcgui.Dialog().ok('错误', '保存授权信息失败！')
        return False

def auto_upgrade():
    try:
        DB_API_URL, SCRIPT_API_URL = build_gitee_api_url()
        if not DB_API_URL or not SCRIPT_API_URL:
            xbmcgui.Dialog().ok('错误', 'API地址构建失败，请检查Token和API地址编码！')
            return
        
        # 修复路径选择逻辑
        if is_coreelec_system():
            db_save_path_enc = 'L3N0b3JhZ2UvLmNvbmZpZy9zeXN0ZW0uZC9NeVZpZGVvcy5kYg=='
        else:
            # 修改非CoreELEC系统的默认路径为用户数据目录下的子目录
            db_save_path_enc = 'c3BlY2lhbDovL3VzZXJkYXRhL2FkZG9uX2RhdGEvc2tpbi5jb25mbHVlbmNlLm1pbnNrL015VmlkZW9zLmRi'
        
        db_save_path = decode_base64_str(db_save_path_enc)
        if not db_save_path:
            # 为不同系统设置合适的默认路径
            if is_coreelec_system():
                db_save_path = '/storage/.config/system.d/MyVideos.db'
            else:
                db_save_path = 'special://userdata/addon_data/skin.confluence.minsk/MyVideos.db'
        
        xbmc.log(f"开始下载数据库文件到: {db_save_path}", level=xbmc.LOGINFO)
        
        download_success = download_file_with_gitee_api(DB_API_URL, db_save_path, overwrite=True)
        if not download_success:
            xbmc.log("数据库文件下载失败，尝试使用本地已存在的文件", level=xbmc.LOGWARNING)
            # 即使下载失败，也尝试检查本地文件是否存在
            if not xbmcvfs.exists(xbmcvfs.translatePath(db_save_path)):
                xbmcgui.Dialog().ok('错误', '数据库文件下载失败，无法继续授权验证！')
                return
        
        # 验证数据库文件是否可访问
        if not check_and_create_database(db_save_path):
            xbmcgui.Dialog().ok('错误', '数据库文件无法访问，可能权限不足或路径错误！')
            return
        
        qq_error_count = 0
        max_error_times = 3
        while True:
            qq_input = xbmcgui.Dialog().input('输入联系方式(QQ号)', type=xbmcgui.INPUT_NUMERIC)
            if qq_input is None or qq_input == '':
                return
            qq_encoded = base64.b64encode(qq_input.encode('utf-8')).decode('utf-8')
            c3_value = query_db(db_save_path, qq_encoded)
            if c3_value is None:
                qq_error_count += 1
                if qq_error_count >= max_error_times:
                    xbmcgui.Dialog().ok('提示', '输入错误次数过多，请核实后再尝试！')
                    return
                xbmcgui.Dialog().ok('提示', f'未找到购买记录！已错误{qq_error_count}次，剩余{max_error_times - qq_error_count}次机会')
                continue
            break
        
        date_error_count = 0
        while True:
            date_input = xbmcgui.Dialog().input('请输入购买时间"年月日"6位数字', type=xbmcgui.INPUT_NUMERIC)
            if date_input is None or date_input == '':
                return
            if len(date_input) != 6 or not date_input.isdigit():
                date_error_count += 1
                if date_error_count >= max_error_times:
                    xbmcgui.Dialog().ok('提示', '输入错误次数过多，请核实后再尝试！')
                    return
                xbmcgui.Dialog().ok('提示', f'格式错误！已错误{date_error_count}次，剩余{max_error_times - date_error_count}次机会\n示例：2025年9月1日输入250901')
                continue
            date_encoded = base64.b64encode(date_input.encode('utf-8')).decode('utf-8')
            if date_encoded != c3_value:
                date_error_count += 1
                if date_error_count >= max_error_times:
                    xbmcgui.Dialog().ok('提示', '输入错误次数过多，请核实后再尝试！')
                    return
                xbmcgui.Dialog().ok('提示', f'购买时间验证失败！已错误{date_error_count}次，剩余{max_error_times - date_error_count}次机会')
                continue
            break
        
        xbmcgui.Dialog().ok('成功', '授权验证通过！皮肤使用授权长期有效，感谢支持！')
        
        xbmc.executebuiltin(f'Skin.SetString(skinauth,{qq_input})')
        xbmc.executebuiltin(f'Skin.SetString(authdate,{date_input})')
        xbmc.executebuiltin('Skin.SetString(authfail,0)')
        
        update_idkey_file(qq_input, date_input)
        
        record_script_path_enc = 'c3BlY2lhbDovL3NraW4vc2NyaXB0cy9yZWNvcmR1cGRhdGUucHk='
        record_script_path = decode_base64_str(record_script_path_enc)
        if not record_script_path:
            record_script_path = 'special://skin/scripts/recordupdate.py'
        script_save_path = xbmcvfs.translatePath(record_script_path)
        
        # 确保脚本目录存在
        script_dir = os.path.dirname(script_save_path)
        if script_dir and not xbmcvfs.exists(script_dir):
            xbmcvfs.mkdirs(script_dir)
        
        if download_file_with_gitee_api(SCRIPT_API_URL, script_save_path, overwrite=True):
            xbmc.executebuiltin(f'RunScript({record_script_path})')
        else:
            xbmcgui.Dialog().ok('提示', '升级脚本下载失败，但授权已生效！')
    
    except Exception as e:
        xbmc.log(f"自动升级失败：{str(e)}", level=xbmc.LOGERROR)
        xbmcgui.Dialog().ok('错误', f'自动升级失败：{str(e)}')

def manual_upgrade():
    try:
        install_zip_cmd_enc = 'SW5zdGFsbEZyb21aaXA='
        install_zip_cmd = decode_base64_str(install_zip_cmd_enc)
        if not install_zip_cmd:
            install_zip_cmd = 'InstallFromZip'
        xbmc.executebuiltin(install_zip_cmd)
    except Exception as e:
        xbmc.log(f"手动升级失败：{str(e)}", level=xbmc.LOGERROR)
        xbmcgui.Dialog().ok('错误', f'执行失败：{str(e)}')

def main():
    dialog = xbmcgui.Dialog()
    choices = [
        '请按照提示输入联系方式(QQ号)开通所有功能',
        '选择zip包升级(需要先将皮肤zip包复制到文件夹)'
    ]
    selected = dialog.select('请选择升级方式', choices)
    if selected == 0:
        auto_upgrade()
    elif selected == 1:
        manual_upgrade()

if __name__ == '__main__':
    try:
        main()
    except Exception as e:
        xbmc.log(f"程序运行出错：{str(e)}", level=xbmc.LOGERROR)
        xbmcgui.Dialog().ok('错误', f'程序运行出错：{str(e)}')