#!/usr/bin/env python
# -*- coding: utf-8 -*-

import os
import sys
import platform
import subprocess
import socket
import urllib.request
import json
import re
import ctypes
from urllib.error import URLError
import time
import threading
import tkinter as tk
from tkinter import ttk, messagebox, scrolledtext

class GithubAccelerator:
    def __init__(self):
        self.hosts_file = self._get_hosts_file_path()
        self.github_domains = [
            'github.com',
            'github.global.ssl.fastly.net',
            'assets-cdn.github.com',
            'raw.githubusercontent.com',
            'gist.githubusercontent.com',
            'cloud.githubusercontent.com',
            'camo.githubusercontent.com',
            'avatars0.githubusercontent.com',
            'avatars1.githubusercontent.com',
            'avatars2.githubusercontent.com',
            'avatars3.githubusercontent.com',
            'avatars4.githubusercontent.com',
            'avatars5.githubusercontent.com',
            'github.githubassets.com',
            'user-images.githubusercontent.com',
            'codeload.github.com',
            'api.github.com'
        ]
        
        self.github_mirrors = {
            "中国内地镜像": [
                {"name": "Gitee", "url": "https://gitee.com/"},
                {"name": "腾讯云", "url": "https://mirrors.cloud.tencent.com/github/"},
                {"name": "CNPMJS", "url": "https://github.com.cnpmjs.org/"}
            ],
            "国际镜像": [
                {"name": "FastGit", "url": "https://hub.fastgit.org/"},
                {"name": "GitHub镜像", "url": "https://githubfast.com/"}
            ]
        }

    def _get_hosts_file_path(self):
        system = platform.system()
        if system == 'Windows':
            return os.path.join(os.environ['SystemRoot'], 'System32', 'drivers', 'etc', 'hosts')
        else:
            return '/etc/hosts'
    
    def _is_admin(self):
        try:
            if platform.system() == 'Windows':
                return ctypes.windll.shell32.IsUserAnAdmin() != 0
            else:
                return os.geteuid() == 0
        except:
            return False
    
    def _get_best_ip(self, domain):
        try:
            # 使用 dns.alidns.com 查询
            url = f"https://dns.alidns.com/resolve?name={domain}&type=A"
            with urllib.request.urlopen(url, timeout=5) as response:
                result = json.loads(response.read().decode('utf-8'))
                if 'Answer' in result:
                    ips = [answer['data'] for answer in result['Answer'] if answer['type'] == 1]
                    if ips:
                        # 测试IP响应时间
                        fastest_ip = None
                        min_time = float('inf')
                        for ip in ips:
                            try:
                                start_time = time.time()
                                socket.create_connection((ip, 80), timeout=2)
                                response_time = time.time() - start_time
                                if response_time < min_time:
                                    min_time = response_time
                                    fastest_ip = ip
                            except:
                                continue
                        if fastest_ip:
                            return fastest_ip
            
            # 如果上面的方法失败，尝试直接解析
            return socket.gethostbyname(domain)
        except Exception as e:
            return None
    
    def update_hosts(self, callback=None):
        if not self._is_admin():
            return "需要管理员权限才能修改hosts文件"
        
        try:
            # 读取当前hosts文件
            with open(self.hosts_file, 'r', encoding='utf-8') as f:
                hosts_content = f.read()
            
            # 删除旧的GitHub条目
            pattern = r"#\s*GitHub Start.*?#\s*GitHub End\s*\n"
            hosts_content = re.sub(pattern, "", hosts_content, flags=re.DOTALL)
            
            # 添加新的GitHub条目
            hosts_content += "\n# GitHub Start\n"

            for i, domain in enumerate(self.github_domains):
                if callback:
                    callback(f"正在获取 {domain} 的最佳IP ({i+1}/{len(self.github_domains)})...")
                ip = self._get_best_ip(domain)
                if ip:
                    hosts_content += f"{ip} {domain}\n"
                    if callback:
                        callback(f"成功: {domain} -> {ip}")
                else:
                    if callback:
                        callback(f"失败: 无法获取 {domain} 的IP地址")

            hosts_content += "# GitHub End\n"
            
            # 写入hosts文件
            with open(self.hosts_file, 'w', encoding='utf-8') as f:
                f.write(hosts_content)
            
            # 刷新DNS缓存
            self._flush_dns()
            
            return "hosts文件更新成功!"
        except Exception as e:
            return f"更新hosts文件时出错: {str(e)}"
    
    def _flush_dns(self):
        system = platform.system()
        try:
            if system == 'Windows':
                subprocess.run(["ipconfig", "/flushdns"], check=True)
            elif system == 'Darwin':  # macOS
                subprocess.run(["killall", "-HUP", "mDNSResponder"], check=True)
            elif system == 'Linux':
                # 尝试几种常见的Linux DNS刷新方法
                try:
                    subprocess.run(["systemd-resolve", "--flush-caches"], check=True)
                except:
                    try:
                        subprocess.run(["service", "network-manager", "restart"], check=True)
                    except:
                        pass
        except:
            pass
    
    def test_github_speed(self):
        try:
            start = time.time()
            with urllib.request.urlopen("https://github.com", timeout=10) as response:
                end = time.time()
                return f"GitHub连接成功，响应时间: {end - start:.2f}秒"
        except URLError as e:
            return f"GitHub连接失败: {str(e)}"

    def get_mirrors_info(self):
        return self.github_mirrors


class GithubAcceleratorGUI:
    def __init__(self, root):
        self.root = root
        self.root.title("GitHub加速器")
        self.root.geometry("600x500")
        self.root.resizable(True, True)
        
        self.accelerator = GithubAccelerator()
        
        self.setup_ui()
    
    def setup_ui(self):
        # 创建选项卡
        self.tab_control = ttk.Notebook(self.root)
        
        self.tab1 = ttk.Frame(self.tab_control)
        self.tab2 = ttk.Frame(self.tab_control)
        self.tab3 = ttk.Frame(self.tab_control)
        
        self.tab_control.add(self.tab1, text="Hosts加速")
        self.tab_control.add(self.tab2, text="镜像站点")
        self.tab_control.add(self.tab3, text="网络检测")
        
        self.tab_control.pack(expand=1, fill="both")
        
        # Hosts加速选项卡
        self.setup_hosts_tab()
        
        # 镜像站点选项卡
        self.setup_mirrors_tab()
        
        # 网络检测选项卡
        self.setup_network_tab()
    
    def setup_hosts_tab(self):
        frame = ttk.Frame(self.tab1, padding="10")
        frame.pack(fill="both", expand=True)
        
        ttk.Label(frame, text="通过更新hosts文件来加速GitHub访问", font=("", 12)).pack(pady=10)
        
        # 状态输出
        self.hosts_log = scrolledtext.ScrolledText(frame, width=60, height=15)
        self.hosts_log.pack(fill="both", expand=True, pady=5)
        self.hosts_log.insert(tk.END, "准备就绪...\n")
        self.hosts_log.config(state="disabled")
        
        # 按钮行
        btn_frame = ttk.Frame(frame)
        btn_frame.pack(fill="x", pady=10)
        
        ttk.Button(btn_frame, text="更新Hosts文件", command=self.update_hosts).pack(side="left", padx=5)
        ttk.Button(btn_frame, text="测试GitHub连接", command=self.test_connection).pack(side="left", padx=5)
        
        # 权限检查
        if not self.accelerator._is_admin():
            self.hosts_log.config(state="normal")
            self.hosts_log.insert(tk.END, "警告: 需要管理员权限才能修改hosts文件！请以管理员身份运行此程序。\n")
            self.hosts_log.see(tk.END)
            self.hosts_log.config(state="disabled")
    
    def setup_mirrors_tab(self):
        frame = ttk.Frame(self.tab2, padding="10")
        frame.pack(fill="both", expand=True)
        
        ttk.Label(frame, text="GitHub镜像站点", font=("", 12)).pack(pady=10)
        
        mirrors = self.accelerator.get_mirrors_info()
        
        # 创建镜像站点列表
        mirrors_frame = ttk.Frame(frame)
        mirrors_frame.pack(fill="both", expand=True)
        
        row = 0
        for category, sites in mirrors.items():
            ttk.Label(mirrors_frame, text=category, font=("", 11, "bold")).grid(row=row, column=0, sticky="w", pady=(10, 5))
            row += 1
            
            for site in sites:
                ttk.Label(mirrors_frame, text=site["name"]).grid(row=row, column=0, sticky="w", padx=20)
                link = ttk.Label(mirrors_frame, text=site["url"], foreground="blue", cursor="hand2")
                link.grid(row=row, column=1, sticky="w")
                link.bind("<Button-1>", lambda e, url=site["url"]: self.open_url(url))
                row += 1
    
    def setup_network_tab(self):
        frame = ttk.Frame(self.tab3, padding="10")
        frame.pack(fill="both", expand=True)
        
        ttk.Label(frame, text="GitHub网络连接检测", font=("", 12)).pack(pady=10)
        
        # 状态输出
        self.network_log = scrolledtext.ScrolledText(frame, width=60, height=15)
        self.network_log.pack(fill="both", expand=True, pady=5)
        self.network_log.insert(tk.END, "准备就绪...\n")
        self.network_log.config(state="disabled")
        
        ttk.Button(frame, text="测试GitHub连接", command=self.test_connection).pack(pady=10)
    
    def update_hosts(self):
        if not self.accelerator._is_admin():
            messagebox.showerror("权限错误", "需要管理员权限才能修改hosts文件！请以管理员身份运行此程序。")
            return
        
        # 清空日志
        self.hosts_log.config(state="normal")
        self.hosts_log.delete(1.0, tk.END)
        self.hosts_log.insert(tk.END, "开始更新hosts文件...\n")
        self.hosts_log.config(state="disabled")
        
        # 在单独的线程中更新hosts
        def update_thread():
            def update_log(message):
                self.hosts_log.config(state="normal")
                self.hosts_log.insert(tk.END, message + "\n")
                self.hosts_log.see(tk.END)
                self.hosts_log.config(state="disabled")
            
            result = self.accelerator.update_hosts(update_log)
            
            # 更新完成后显示结果
            self.hosts_log.config(state="normal")
            self.hosts_log.insert(tk.END, f"\n{result}\n")
            self.hosts_log.see(tk.END)
            self.hosts_log.config(state="disabled")
        
        threading.Thread(target=update_thread).start()
    
    def test_connection(self):
        # 在网络选项卡上测试
        self.network_log.config(state="normal")
        self.network_log.insert(tk.END, "正在测试GitHub连接...\n")
        self.network_log.config(state="disabled")
        
        def test_thread():
            result = self.accelerator.test_github_speed()
            
            self.network_log.config(state="normal")
            self.network_log.insert(tk.END, f"{result}\n")
            self.network_log.see(tk.END)
            self.network_log.config(state="disabled")
            
            # 同时更新hosts选项卡上的日志
            self.hosts_log.config(state="normal")
            self.hosts_log.insert(tk.END, f"GitHub连接测试: {result}\n")
            self.hosts_log.see(tk.END)
            self.hosts_log.config(state="disabled")
        
        threading.Thread(target=test_thread).start()
    
    def open_url(self, url):
        import webbrowser
        webbrowser.open(url)


def main():
    # 检查是否为管理员权限
    if platform.system() == 'Windows' and not ctypes.windll.shell32.IsUserAnAdmin():
        # 尝试重新以管理员权限运行
        try:
            ctypes.windll.shell32.ShellExecuteW(None, "runas", sys.executable, " ".join(sys.argv), None, 1)
            sys.exit(0)
        except:
            pass
    
    root = tk.Tk()
    app = GithubAcceleratorGUI(root)
    root.mainloop()

if __name__ == "__main__":
    main() 