import json
import sys
import os
import subprocess
# from datetime import datetime
import socket
import requests
import time

def execute(cmd) -> tuple[int, str]:
   return subprocess.getstatusoutput(cmd)

def upload_file(url, file_path):
    try:
        dirname, filename = os.path.split(file_path)
        with open(file_path, 'rb') as file:
            files = {'data': (filename, file)}
            response = requests.post(url, files=files)
            return response.text
    except Exception as e:
        print(f"上传失败: {e}")
        return None
    
def download_file(url, save_path):
    try:
        response = requests.get(url, stream=True)
        response.raise_for_status()
        with open(save_path, 'wb') as file:
            for chunk in response.iter_content(chunk_size=8192):
                if chunk: 
                    file.write(chunk)
        return True
    except Exception as e:
        print(f"下载失败: {e}")
        return False

def send_post_request(url, data=None, json=None, headers=None):
    try:
        response = requests.post(url, data=data, json=json, headers=headers)
        # print(response.status_code, response.text)
        return (response.status_code, response.text)
    except requests.exceptions.RequestException as e:
        print(f"请求失败: {e}")
        return None

def load_info(id: str):
    (_, t_cpu) = execute("cat /proc/cpuinfo | grep \"^Serial.*:\" | awk '{print $3}'")
    (_, t_kernel) = execute("uname -r")
    (_, t_os) = execute("cat /etc/os-release | grep VERSION_CODENAME | awk -F'=' '{print $2}'")
    (_, t_power) = execute("dpkg -l | grep ed-codesys-[0-9][0-9][0-9] | awk '{print $2}' | awk -F '-' '{print $3}'")
    # now = datetime.now()
    return {
        "name": id,
        "os": t_os,
        "cpu": t_cpu,
        "kernel": t_kernel,
        "power": t_power,
        # "create": now.strftime("%Y/%m/%d %H:%M:%S")
    }

def create_key():
    print("[Debug]开始生成公钥...")
    return os.system("mkdir -p /etc/eda && cd /etc/eda/ && eda-codesys") == 0
        

def run(id: str, timeout: int = 3):
    t_ip = None
    t_port = 7200
    t_retry = timeout * 2
    t_result = False
    try:
        sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
        sock.settimeout(0.5)
        sock.bind(('0.0.0.0', 7002))
        for i in range(t_retry):
            try:
                data, addr = sock.recvfrom(1024)
                msg = data.decode()
                if msg.startswith("[codesys]Server,") and msg.endswith(",end"):
                    items = msg.split(",")
                    t_ip = items[1]
                    t_port = items[2]
                    break
            except Exception:
                # print("超时...")
                pass
    finally:
        sock.close()
    if t_ip is None:
        print("[Error] 没有找到授权服务器.")
        exit(2)
    print("[Debug]开始自动授权...")
    bRunning = True
    for i in range(2):
        # 生成key
        for i in range(3):
            if create_key():
                break
            time.sleep(1)
        # 上传Key
        print("[Debug] 开始上传key...")
        msg = upload_file(f"http://{t_ip}:{t_port}/key/{id}", "/etc/eda/eda-rsa.pub")
        print("upload key",msg)
        if msg is not None and msg.endswith(".dat"):
            print("[Debug] 上传key成功.")
            for i in range(3):
                print(f"[Debug][{i}] 开始下载授权...")
                if download_file(f"http://{t_ip}:{t_port}/downloads/{id}/{msg}", "/etc/eda/eda-v1.dat"):
                    print(f"[Debug][{i}] 下载授权成功")
                    t_info = load_info(id)
                    for j in range(3):
                        print(f"[Debug][{j}] 上传设备信息...")
                        (state, msg1) = send_post_request(f"http://{t_ip}:{t_port}/device/{id}", json= t_info)
                        if state == 200 and msg1 == "0":
                            print("[Debug]自动授权完成")
                            print("[Debug] 开始备份授权...")
                            for k in range(3):
                                (state, msg) = execute(f"zip /tmp/{id}.zip /etc/eda/* -x '/etc/eda/3S.dat'")
                                if state == 0:
                                # if os.system(f"zip /tmp/{id}.zip /etc/eda/* -x '/etc/eda/3S.dat'"):
                                    print(f"[Debug][{k}] 开始上传授权备份...")
                                    msg2 = upload_file(f"http://{t_ip}:{t_port}/backup/{id}", f"/tmp/{id}.zip")
                                    if msg2 is not None and msg2 == "0":
                                        print("[Debug] 备份授权完成")
                                        bRunning = False
                                        t_result = True
                                        break
                                    else:
                                        print("[Error] 上传授权备份失败")
                                else:
                                    bRunning = False
                                    break
                                if not bRunning:
                                    break
                            if not bRunning:
                                break
                        else:
                            print("[Error] 上传设备信息失败")
                    if not bRunning:
                        break
                else:
                    print("[Error] 重新下载授权.")
        else:
            print("[Debug] 上传key失败.")
        if not bRunning:
            break
    return t_result

if __name__ == "__main__":
    t_result = False
    if len(sys.argv) == 1:
        sn = input("请输入设备SN: ")
        t_result = run(sn)
    elif len(sys.argv) == 2:
        t_result = run(sys.argv[1])
    elif len(sys.argv) == 3:
        timeout = 3
        if len(sys.argv) == 3:
            try:
                timeout = int(sys.argv[2])
            except Exception:
                print(f"run: {sys.argv[0]} sn [timeout]")
                exit(2)
        t_result = run(sys.argv[1], timeout)
    else:
        print(f"run: {sys.argv[0]} sn [timeout]")
        exit(1)
    if not t_result:
        exit(1)
