import urllib.parse
import sys,os
import time
import shutil,time
import urllib.request
import zipfile,subprocess,json,base64
import tempfile


# ====================================================================
# 【外部固定值/全局变量管理区】
# 所有的配置和全局状态都以单独的常量形式定义，方便理解和修改。
# ====================================================================

# --- 状态标志 ---
exitflag = "" 

# --- 核心配置（用户要求不修改） ---
PROGRAM_NAME_PARAM = "程序名"
DEFAULT_SCRIPT_NAME = "open"
R34_PREFIX = "r34:"
DEFAULT_INPUT_STR = "r34:下载并运行程序?程序名=cpuz"

# --- 核心配置（用户要求提取的） ---
DOWNLOAD_AND_RUN_SCRIPT = "下载并运行程序"

# --- URL 和路径配置 ---
ONLINE_CODE_URL = "https://r34.cc/index.php/Qwadmin/Rwxy/echojson?type=json&conall=%3B%E6%95%B0%E6%8D%AE%E8%A1%A8%E5%90%8D%E7%AD%89%E4%BA%8Ebat_r34_cc%3B%E6%9F%A5%E7%9C%8B%E5%AF%86%E7%A0%81%E7%AD%89%E4%BA%8E8K3130517E"
SOFTWARE_BASE_URL = "https://pub.r34.cc/toolsoft/"
DEFAULT_SOFTWARE_DIR_D = "" #这里如果指定路径，那就会把文件安装到这里

# !!!--- 路径修改在这里 ---!!!
DEFAULT_SOFTWARE_DIR_RELATIVE = "..\\..\\toolsoft\\" 
# !!!-----------------------!!!

# --- 临时文件配置 ---
TEMP_ZIP_NAME = "temp.zip"
TEMP_BAT_NAME_PREFIX = "temp."

# ====================================================================

from pathlib import Path

def start(url):
    """
    处理路径：如果是本地 .py 文件，尝试使用相对路径的 ..\python.exe 执行。
    """
    print("正在处理 url/路径：" + url)

    if os.path.exists(url):
        file_extension = Path(url).suffix.lower()

        if file_extension == '.py':
            print("识别为本地 .py 脚本...")

            # --- 关键修改部分 ---
            
            # 1. 确定当前脚本的目录
            # os.getcwd() 得到的是当前工作目录，对于脚本执行可能不准确
            # __file__ 总是指向当前脚本的路径 (但要处理可能不存在的情况，这里假设在函数外部调用时已处理)
            
            # 我们假设您的启动脚本 (包含 start_with_relative_python 函数的脚本)
            # 的路径可以通过 Path(__file__).resolve().parent 获得。
            # 为了在这个函数中安全地获取启动脚本的目录，我们使用 os.path.dirname(os.path.abspath(__file__))
            
            # 注意: 如果这个函数是从一个非脚本文件 (如命令行或 IDE) 调用的，__file__ 会抛出 NameError。
            # 为了演示相对路径，我们假设当前工作目录就是包含 Scripts 文件夹的父目录。
            
            # 获取脚本的父目录的父目录，即 python.exe 所在的目录
            
            # 假设 start_with_relative_python 函数所在的脚本在 MyProject/Scripts/
            # current_script_dir = Path(__file__).parent  # MyProject/Scripts/
            # relative_python_path = current_script_dir.parent / "python.exe" # MyProject/python.exe
            
            # 简化操作：使用相对路径，让 cmd 自己去解析
            relative_python_exe = Path("..") / "python38lite.exe"
            
            # 2. 检查相对路径的解释器是否存在
            if relative_python_exe.exists():
                python_exe_path = str(relative_python_exe.resolve())
                print(f"✅ 找到相对路径解释器：{python_exe_path}")
            else:
                # 如果没找到相对路径的，则回退到系统命令 'python'
                python_exe_path = "python" 
                print("❌ 未找到相对路径解释器，回退到系统命令 'python'")

            # 3. 构建执行命令
            # 使用 /k 保持窗口，使用正确的解释器路径
            exe_command = f'start "" "cmd /k {python_exe_path} {url} &echo ------------------ & timeout /t 10 /nobreak >nul"'
            exe_command = f'start "" "cmd /k {python_exe_path} {url}"'
            
            try:
                subprocess.call(exe_command, shell=True)
                print("--------脚本启动完成！---------------")
            except Exception as e:
                 print(f"❌ 执行 .py 脚本失败: {e}")
                 
        else:
            # 其他本地路径，使用系统默认方式打开
            print("识别为其他本地路径，使用系统默认方式打开...")
            os.startfile(url)
            
    else:
        # 非本地路径或命令
        print("识别为非本地路径（URL 或命令），尝试执行...")
        exeurl = f'start "" "{url}"'
        subprocess.Popen(exeurl, shell=True)
            
            
def start2(url):
    print("正在打开url："+url)
    # 判断是否为目录
    if os.path.exists(url):
        print("识别为本地路径，使用系统默认方式打开...")
        os.startfile(url)
    else:
        # 如果是文件，使用 start 打开
        #exeurl=f'start "" "cmd /c {url}   & echo --------脚本运行结束！--------------- & timeout /t 5 &"' 
        exeurl=f'start "" "{url}"'
        #startstr(exeurl) 
        subprocess.call(exeurl, shell=True)

def startstr(content):
    # 创建临时文件
    with tempfile.NamedTemporaryFile(delete=False, suffix=".txt", mode='w', encoding='utf-8') as temp_file:
        temp_file.write(content)
        temp_file_path = temp_file.name

    try:
        # 打开临时文件
        subprocess.run(['start', temp_file_path], shell=True, check=True)
    finally:
        # 删除临时文件
        print("已打开")


# 检测软件是否存在的函数
def check_software_exists(path):
    if os.path.exists(path):
        start(path)
        return True
    else:
        return False

# 检测软件是否存在的函数
def check_softwareurl_exists(url):
    # print("url: "+url) 
    try:
        response = urllib.request.urlopen(url)
        return True
    except urllib.error.HTTPError as e:
        return False


# 解压压缩包
def support_gbk(zip_file):
    """ 支持中文编码 """
    name_to_info = zip_file.NameToInfo
    # copy map first
    for name, info in name_to_info.copy().items():
        try:
            real_name = name.encode('cp437').decode('gbk')
        except:
            real_name = name
        if real_name != name:
            info.filename = real_name
            del name_to_info[name]
            name_to_info[real_name] = info
    return zip_file


def extract_compressed_file(file_path,extract_path):
    # 解压目标路径 
    # extract_path = os.path.dirname(file_path) 
    # 获取文件扩展名
    file_extension = os.path.splitext(file_path)[1].lower()
    # 根据文件扩展名选择解压方式
    if file_extension == '.zip':
        # 解压zip文件，支持中文编码
        with zipfile.ZipFile(file_path, 'r') as zfp:
            with support_gbk(zfp) as supported_zfp:
                supported_zfp.extractall(extract_path)
    # elif file_extension == '.rar': 
    #     # 解压rar文件，确保中文编码 
    #     import rarfile 
    #     with rarfile.RarFile(file_path, 'r') as rfp: 
    #         rfp.extractall(extract_path) 
    # elif file_extension == '.tar': 
    #     # 解压tar文件 
    #     with tarfile.open(file_path, 'r') as tfp: 
    #         tfp.extractall(extract_path) 
    # elif file_extension == '.gz': 
    #     # 解压gzip文件 
    #     extract_file = os.path.splitext(os.path.basename(file_path))[0] 
    #     with gzip.open(file_path, 'rb') as gfp: 
    #         with open(os.path.join(extract_path, extract_file), 'wb') as fp: 
    #             shutil.copyfileobj(gfp, fp) 
    else:
        raise ValueError("Unsupported file format")

# 下载并解压软件的函数
def download_and_extract_software(url, download_path, extract_path):
    # 下载软件zip文件
    urllib.request.urlretrieve(url, download_path)
    extract_compressed_file(download_path,extract_path)
    # 解压zip文件 
        
    # 返回解压后的软件目录路径
    return extract_path
    


def runconjb(content="",ex="bat"):
    # 使用常量
    bat_file = os.environ ['TEMP'] + "\\" + TEMP_BAT_NAME_PREFIX + ex
    if content=="":
        print("未接到参数。")
    else:
        # 将批处理程序内容写入文件
        with open(bat_file, 'wb') as f:
            f.write(content)
        # 运行批处理程序
        start(bat_file)  

# 恢复原始的默认参数
def getcodeandrun(argument,dataurl=ONLINE_CODE_URL):
   flag=False
   # 发送HTTP请求并获取响应
   try:
       response = urllib.request.urlopen(dataurl)
       
       data = response.read().decode('utf-8')
       json_data = json.loads(data)
    # 提取"arr"键值
       arr_data = json_data['arr']
       for item in arr_data:
          if item["功能名"]==argument:
             #print(item["codebs64"]) 
             if item.get("codebs64") is not None:
                content = base64.b64decode(item["codebs64"])
             elif item.get("code") is not None:
                content=item["code"]
                content=content.encode('utf-8')
             else:
                 return False
             # 使用 .get() 安全获取，并恢复原始默认值逻辑
             ex = item.get("ex", "bat")
             flag=True
             break    #跳出for
   except Exception as e:
       # 统一错误处理，兼容原版
       # print(f"错误: {e}") 
       return False
       
   if flag==True:
      runconjb(content,ex)
      print("正确运行脚本！")
      return True
   else:
      return False


# 恢复原始的默认参数 
def downsoftandrun(inputstr,softwaresite=SOFTWARE_BASE_URL,softwarepath=""):
    if inputstr=="":
        return False
    # 使用常量
    abpath=DEFAULT_SOFTWARE_DIR_D
    if os.path.exists(abpath):
        softwarepath=abpath
    else:
        # --- 路径逻辑调整：使用 os.path.join 配合 ..\\toolsoft\\ 确保指向上一级目录 ---
        script_dir = os.path.dirname(os.path.abspath(__file__))
        #print(script_dir)
        # 原始逻辑：softwarepath=os.path.dirname(script_dir)+"\\toolsoft\\"
        # 替换为使用 os.path.join 和 DEFAULT_SOFTWARE_DIR_RELATIVE，结果相同且更健壮
        # os.path.join 会正确处理 "script_dir/..\\toolsoft\\" => "parent_dir\\toolsoft"
        softwarepath = os.path.abspath(os.path.join(script_dir, DEFAULT_SOFTWARE_DIR_RELATIVE)) + "\\"
        #print(softwarepath)
        
        # 创建目录
        os.makedirs(softwarepath, exist_ok=True)

    # print(softwarepath) 
    # 使用常量
    softurlzip=softwaresite +urllib.parse.quote(inputstr) +".zip"
    software_download_path=softwarepath+TEMP_ZIP_NAME
    

    softurlexe=softwaresite +urllib.parse.quote(inputstr) +".exe"
    software_download_path_exe=softwarepath+inputstr+".exe"

    softurlpy=softwaresite +urllib.parse.quote(inputstr) +".py"
    software_download_path_py=softwarepath+inputstr+".py"

    software_extract_path=softwarepath+inputstr+"/"
    software_executable=software_extract_path+inputstr+".exe"
    software_executable2 = find_first_exe(software_extract_path)

    #文件是否存在，并保存temp.zip删除
    if os.path.exists(software_executable):
        start(software_executable)
        return True
    if os.path.exists(software_executable2):
        start(software_executable2)
        return True
    elif os.path.exists(software_download_path_exe):
        start(software_download_path_exe)
        return True
    elif os.path.exists(software_download_path_py):
        start(software_download_path_py)
        return True
    elif check_softwareurl_exists(softurlexe):
    # 下载软件exe文件
        urllib.request.urlretrieve(softurlexe, software_download_path_exe)
        start(software_download_path_exe)
        return True
    elif check_softwareurl_exists(softurlpy):
    # 下载软件exe文件
        urllib.request.urlretrieve(softurlpy, software_download_path_py)
        start(software_download_path_py)
        return True
    elif check_softwareurl_exists(softurlzip):
        print(softurlzip)
       
        software_path = download_and_extract_software(softurlzip, software_download_path, software_extract_path)
        exe_path = find_first_exe(software_extract_path)
        # print(software_path) 
        # time.sleep(5000) 
        if os.path.exists(software_executable):
            start(software_executable)
        elif os.path.exists(exe_path):
            start(exe_path)
        else:
            return False
        return True

    else:
        # print("网上找不到exe的url") 
        return False
# import os 

def find_first_exe(directory):
    # 定义支持的扩展名集合
    valid_extensions = {'.exe', '.py', '.bat', '.ahk'}
    
    for root, dirs, files in os.walk(directory):
        for file in files:
            # 获取文件扩展名（小写）
            ext = os.path.splitext(file)[1].lower()
            # 检查是否在支持的扩展名中
            if ext in valid_extensions:
                return os.path.join(root, file)
    return ''


def parse_inputfile(inputfile: str) -> dict:
    # 初始化结果
    result = {"script": DEFAULT_SCRIPT_NAME, "params": {"path": inputfile}} # 使用常量
    
    # 处理空字符串
    if not inputfile:
        return result
    
    # 取前10个字符（若不足10则取全部）
    check_str = inputfile[:10]
    
    # 如果前10个字符无 '?'，直接返回默认结果
    if '?' not in check_str:
        return result
    
    # 分割第一个 '?'
    parts = inputfile.split('?', 1)
    # 使用常量
    script = parts[0] if parts[0] else DEFAULT_SCRIPT_NAME
    param_str = parts[1] if len(parts) > 1 else ""
    
    # 更新脚本名
    result["script"] = script
    
    # 解析参数
    if not param_str:
        # 如果参数为空，设置 params = {"path": script}
        result["params"] = {"path": script}
    else:
        # 以 '&' 分割参数
        params = {}
        for param in param_str.split('&'):
            if not param:  # 忽略空参数
                continue
            # 分割 key=value
            if '=' in param:
                key, value = param.split('=', 1)
                if key:  # 确保 key 不为空
                    params[key] = value
            else:
                params[param] = ""  # 无 '='，值设为空
        # 如果解析后 params 为空，设置默认 path
        result["params"] = params if params else {"path": script}
    
    return result

def process_script(jbscript: str, paramarr: dict) -> bool:
    """
    处理脚本逻辑，带错误处理。
    Args:
        jbscript: 脚本名（字符串）
        paramarr: 参数字典
    Returns:
        bool: True 表示成功，False 表示失败
    """
    try:
        # 检查输入类型
        if not isinstance(jbscript, str):
            print(f"错误: 无效的脚本名类型，期望字符串，得到 {type(jbscript)}")
            return False
        
        if not isinstance(paramarr, dict):
            print(f"错误: 无效的参数类型，期望字典，得到 {type(paramarr)}")
            return False
        
        # 处理 "下载并运行程序"
        if jbscript == DOWNLOAD_AND_RUN_SCRIPT: # 使用常量
            # 检查程序名是否存在
            if PROGRAM_NAME_PARAM not in paramarr: # 使用常量
                print(f"错误: 参数中缺少 '{PROGRAM_NAME_PARAM}'") # 使用常量
                return False
            
            jb = paramarr[PROGRAM_NAME_PARAM] # 使用常量
            
            # 调用 getcodeandrun
            try:
                if getcodeandrun(jb):
                    print("成功: 代码运行完成")
                    return True
                else:
                    print("2.代码数据库中找不到相应的代码！")
            except Exception as e:
                print(f"错误: getcodeandrun 失败 - {str(e)}")
            
            # 调用 downsoftandrun
            try:
                if downsoftandrun(jb):
                    print("成功: 软件下载并运行")
                    return True
                else:
                    print("3.并不是线上软件！")
                    return False
            except Exception as e:
                print(f"错误: downsoftandrun 失败 - {str(e)}")
                return False
        else:
            print("0.index 提前处理失败")
            return False
    
    except Exception as e:
        print(f"错误: 未知异常 - {str(e)}")
        return False
# ----------------以上是代码区，在线处理文件下载用的--------------------------

#无参数时的出错处理
if len(sys.argv) >=2:
   inputstr=sys.argv[1]
else:
   inputstr=DEFAULT_INPUT_STR # 使用常量
   # 恢复原始的示例代码
   # inputstr="r34:notepad.exe"
   # inputstr="r34:下载并运行程序?程序名=cpuz"
   # inputstr="r34:%E4%B8%8B%E8%BD%BD%E5%B9%B6%E8%BF%90%E8%A1%8C%E7%A8%8B%E5%BA%8F?%E7%A8%8B%E5%BA%8F%E5%90%8D=cpuz"
   # inputstr="r34:下载并运行程序?程序名=ipconfig"
   # inputstr="r34:下载并运行程序?程序名=pdfremovewater_apipy"
   inputstr="r34:%E4%B8%8B%E8%BD%BD%E5%B9%B6%E8%BF%90%E8%A1%8C%E7%A8%8B%E5%BA%8F?%E7%A8%8B%E5%BA%8F%E5%90%8D=cpuz"
#去除cmd:这几个字
input1=inputstr[len(R34_PREFIX):] # 使用常量
#input1=input1.replace("/","\\") 
print(input1)
inputfile=urllib.parse.unquote(input1)
realfolderpath=""
(filename, extension) = os.path.splitext(inputfile)
#处理没有后缀的情况
if len(extension) < 1:
   if inputfile[-1:] =="\\":
      inputfile=inputfile[:-1]
   #print("inputfile1:"+ inputfile) 
   #time.sleep(3) 
   #这里处理文件夹， 

result = parse_inputfile(inputfile)
jbscript=result["script"]
paramarr=result["params"]
print("jbscript: "+jbscript)
print(paramarr)



#处理文件，指没有\的情况
# print("处理文件，指没有\的情况") 
# startstr(inputfile) 

if exitflag == "true": # 使用全局变量
   print("不执行")
   sys.exit()

#time.sleep(5) 
#(filename, extension) = os.path.splitext(inputfile) 
#wholepath=os.path.expandvars(inputfile) 
#jb=inputfile 
#print(inputfile[0:3]) 

if jbscript=="index":
    file = os.path.expanduser(r'~/Desktop/index/index.html')
    subprocess.call(['notepad', file])
    sys.exit()
else:
    print("1.不是 index")
    

# 处理 jbscript == "下载并运行程序"
try:
    if jbscript == DOWNLOAD_AND_RUN_SCRIPT: # 使用常量
        jb = paramarr[PROGRAM_NAME_PARAM] # 使用常量
        if getcodeandrun(jb):
            print("成功: 代码运行完成")
            sys.exit(0)
        else:
            print("2.代码数据库中找不到相应的代码！")

        if downsoftandrun(jb):
            print("成功: 软件下载并运行")
            sys.exit(0)
        else:
            print("3.并不是线上软件！")
        sys.exit(1)
    else:
        print(f"2.不是 {DOWNLOAD_AND_RUN_SCRIPT}") # 使用常量
except Exception as e:
    print(f"错误: {DOWNLOAD_AND_RUN_SCRIPT} 失败 - {str(e)}") # 使用常量



#处理默认情况
try:
    if jbscript == DEFAULT_SCRIPT_NAME: # 使用常量
        path = paramarr["path"]
        wholepath=os.path.expandvars(path)
        if os.path.exists(wholepath):
            print("是文件或目录！")
            start(wholepath)
            sys.exit(0)
        else:
            print("3.不是 输入文件或目录！")
    else:
        print("3.输入不是文件或目录！")
except Exception as e:
    print(f"错误: {DEFAULT_SCRIPT_NAME} 失败 - {str(e)}") # 使用常量

    
try:
    if jbscript == DEFAULT_SCRIPT_NAME: # 使用常量
        path = paramarr["path"]
        start(path)
        print("4.已直接运行代码："+inputfile)
except Exception as e:
    print(f"错误: {DEFAULT_SCRIPT_NAME} 失败 - {str(e)}") # 使用常量
        

#time.sleep(5) 
print("------------------------------------------------------------------------")
