'''
  Hey,don't import me! I am for internal use. 
  -------------------------------------
  Project Tongji-EasyAPI
  offlineCaptcha.py
  Copyright (c) 2022 Cinea Zhan. All rights reserved
  www.cinea.com.cn
'''

#  不幸的是，使用打码平台处理ids系统的验证码并不是一个明智的选择
#  因此编写了这个offlineCaptcha系统，希望能通过用户手动点选以完成1系统的验证


from http.server import HTTPServer,BaseHTTPRequestHandler
import os,threading,json,re,time,webbrowser
from urllib.parse import unquote
import inspect,ctypes

#进程停止代码

def _async_raise(tid, exctype):
    """raises the exception, performs cleanup if needed"""
    tid = ctypes.c_long(tid)
    if not inspect.isclass(exctype):
        exctype = type(exctype)
    res = ctypes.pythonapi.PyThreadState_SetAsyncExc(tid, ctypes.py_object(exctype))
    if res == 0:
        raise ValueError("invalid thread id")
    elif res != 1:
        """
        if it returns a number greater than one, you're in trouble,
        and you should call it again with exc=NULL to revert the effect
        """
        ctypes.pythonapi.PyThreadState_SetAsyncExc(tid, None)
        raise SystemError("PyThreadState_SetAsyncExc failed")

def stop_thread(thread):
    _async_raise(thread.ident, SystemExit)

host = ('127.0.0.1',810)
httpfilepath = os.path.dirname(os.path.abspath(__file__))+"/web"  #web文件路径

#使用全局变量通信
stopFlag = False  
heartBeat = False
stopReason = 0  #0:自动中断；1:用户中断
imageb64 = ""
wordList = ""
result = []

#本地Server

class localCaptchaServer(BaseHTTPRequestHandler):

    finished = False

    #GET处理文件请求
    def do_GET(self):
        path = str(self.path)
        try:
            with open(httpfilepath+path,"rb") as f:
                fileContent = f.read()
            self.send_response(200)
            self.send_header("content-type","*/*")
            self.end_headers()
            self.wfile.write(fileContent)
        except:
            self.send_error(404,"File Not Found")
    
    #POST处理api请求
    def do_POST(self):
        global stopFlag,stopReason
        path = str(self.path)
        command = re.findall(r"^/api/(.*?)$",path)
        if len(command)==0:
            self.send_error(400,"Bad Request")
        else:
            command = command[0]
            if command == "hello":
                #开发调试用
                self.send_response(200)
                self.send_header("content-type","text/plain")
                self.end_headers()
                self.wfile.write("Hello!".encode())
            elif command == "heartbeat":
                self.send_response(200)
                self.send_header("content-type","text/plain")
                self.end_headers()
                self.wfile.write("Ok!".encode())
                if not self.finished:
                    stopFlag = False
            elif command == "getdata":
                self.send_response(200)
                self.send_header("content-type","application/json")
                self.end_headers()
                self.wfile.write(json.dumps({"imageBase64":imageb64,"wordsList":wordList}).encode())
            elif "submit" in command:
                command = unquote(command)
                jsonData = re.findall(r"json=(.*)",command)
                try:
                    jsonData = json.loads(jsonData[0])
                    global result
                    result = jsonData["result"]
                    self.send_response(200)
                    self.send_header("content-type","text/plain")
                    self.end_headers()
                    self.wfile.write("ok".encode())
                    self.finished = True
                    stopFlag = True
                    stopReason = 0
                except:
                    self.send_error(400,"Bad request")
            else:
                self.send_error(404,"Command not found")

class checkFinishThread(threading.Thread):
    def __init__(self,server):
        self.server = server
        super().__init__()

    def run(self):
        global stopFlag
        time.sleep(5) #等待浏览器和http server启动
        while not stopFlag:
            stopFlag = True
            time.sleep(1)
        self.server.shutdown()

class openBrowserThread(threading.Thread):
    """
    使用线程打开浏览器的原因：希望能够延时几秒防止打开浏览器后后端服务未启动导致404
    """
    def __init__(self):
        self.opened=False
        super().__init__()
    
    def run(self):
        if not self.opened:
            time.sleep(1.5)
            webbrowser.open("http://127.0.0.1:810/index.html",new=1)
            self.opened=True


#初始化/重新初始化app
def captchaOfflineBreaker(imagebs64:str,clickwords:list[str]) -> dict:
    """
    @return: 返回一个字典。字段"result":结果，"reason"退出原因，为1时需中断验证过程并切断登陆。
    """
    #重置全局变量
    print("call")
    global stopFlag,imageb64,wordList,result
    stopFlag = False
    imageb64 = imagebs64
    wordList = ",".join(clickwords)
    result = []

    server = HTTPServer(host, localCaptchaServer)
    checking = checkFinishThread(server)
    browserThread = openBrowserThread()
    browserThread.start()
    checking.start()
    server.serve_forever()

    #检查结果有效性
    try:
        result[0]["x"],result[0]["y"]
        result[1]["x"],result[1]["y"]
        result[2]["x"],result[2]["y"]
    except:
        result=[{"x":0,"y":0},{"x":0,"y":0},{"x":0,"y":0}]
    
    # stop_thread(browserThread)
    # stop_thread(checking)

    return {"result":result,"reason":stopReason}
    
if __name__=="__main__":
    with open("image.jpg","rb") as f:
        imageb64 = f.read()
    import base64
    imageb64 = base64.b64encode(imageb64).decode("utf-8")
    captchaOfflineBreaker(imageb64,["我","尼","马"])