import asyncio
from threading import Thread
from time import sleep, ctime
from co6co.utils import log
from functools import partial
from types import FunctionType
from co6co.utils import isCallable


class ThreadEvent:
    """
    线程Event loop 
    Run Event Loop in different thread.

    ## 因某些原因写了该类 
    ## 1. asyncio.run 在 没有正在运行的事件循环 的情况下运行协程的
        ## wx_user_dict:list[dict]=asyncio.run(bll.get_subscribe_alarm_user(config.appid)) 
        ## alarm= alarm_bll(app)
        ## po:bizAlarmTypePO=asyncio.run(alarm.get_alram_type_desc(po.alarmType))
        ## 2. 正在运行的事件循环
        ## This event loop is already running   
        ## import nest_asyncio 
        ## loop = asyncio.get_event_loop()
        ## wx_user_dict:list[dict]=loop.run_until_complete(bll.get_subscribe_alarm_user(config.appid)) 

        ## 3. 创建任务
        ## task=asyncio.create_task(bll.get_subscribe_alarm_user(config.appid))
        ## wx_user_dict:list[dict]=asyncio.run(task) 
        ## 4.底层使用
        ## asyncio.ensure_future(coro())
        ## 5. 
    """
    @property
    def loop(self):
        return self._loop

    bck: FunctionType = None

    def __init__(self, threadName: str = None, quitBck: FunctionType = None):
        self._loop = asyncio.new_event_loop()
        # log.warn(f"ThreadEventLoop:{id(self._loop)}")
        Thread(target=self._start_background, daemon=True, name=threadName) .start()
        self.bck = quitBck

    def _start_background(self):
        asyncio.set_event_loop(self.loop)
        self._loop.run_forever()
        if self.bck != None and isCallable(self.bck):
            self.bck()

    def runTask(self, tastFun, *args, **kwargs):
        # log.warn(f"ThreadEventLoop22:{id(self._loop)}")
        task = asyncio.run_coroutine_threadsafe(tastFun(*args, **kwargs), loop=self._loop)
        return task.result()

    def _shutdown(self):
        self._loop.stop()
        # print("running:", self._loop.is_running()) #True
        # print("closed.", self._loop.is_closed())   #False

    def close(self):
        self._loop.call_soon_threadsafe(partial(self._shutdown))

    def __del__(self):
        self._loop.close()
        # log.warn("closed")
        # print("running:", self._loop.is_running()) #False
        # print("closed.", self._loop.is_closed())   #True


class Executing:
    """
    线程 自己执行自己退出
    """
    _starting: bool = None

    @property
    def loop(self):
        return self._loop

    @property
    def runing(self):
        return self._starting

    bck: FunctionType = None
    args = None
    kvgs = None

    def __init__(self, threadName: str, func, *args, **kvgs):
        '''
        threadName: 线程名
        func: 执行的方法 async 
        args:  func 参数
        kvgs: func 参数
        '''
        self._loop = asyncio.new_event_loop()
        self._isCallClose = False
        self.threadName = threadName
        self.bck = func
        self.args = args
        self.kvgs = kvgs
        Thread(target=self._start_background, daemon=True, name=threadName) .start()

    def _start_background(self):
        try:
            asyncio.set_event_loop(self.loop)
            log.log("线程'{}->{}'运行...".format(self.threadName, id(self.loop)))
            self.loop.run_until_complete(self.bck(*self.args, **self.kvgs))
            # await self.bck(*self.args,**self.kvgs)
        except Exception as e:
            log.warn("线程'{}->{}'执行出错".format(self.threadName, id(self.loop)))
        finally:
            log.log("线程'{}->{}'结束.".format(self.threadName, id(self.loop)))
            self.loop.close()


class TaskManage:
    _starting: bool = None

    @property
    def loop(self):
        return self._loop

    @property
    def runing(self):
        return self._starting

    bck: FunctionType = None

    def __init__(self, threadName: str = None):
        self._loop = asyncio.new_event_loop()
        self._isCallClose = False
        self.threadName = threadName
        Thread(target=self._start_background, daemon=True, name=threadName) .start()

    def _start_background(self):
        asyncio.set_event_loop(self.loop)
        log.log("线程'{}->{}'运行...".format(self.threadName, id(self.loop)))
        self._starting = True
        self._loop.run_forever()
        log.log("线程'{}->{}'结束.".format(self.threadName, id(self.loop)))
        self._starting = False

    def runTask(self, tastFun, callBck, *args, **kwargs):
        """
        不能回调 调用 close 因为还在执行中.
        """
        # log.warn(f"ThreadEventLoop22:{id(self._loop)}")
        # run_coroutine_threadsafe 从非事件循环线程向事件循环线程提交协程任务
        task = asyncio.run_coroutine_threadsafe(tastFun(*args, **kwargs), loop=self._loop)
        # .result() 方法等待协程的结果，或者使用 .add_done_callback() 添加回调来处理结果。
        if callBck != None:
            task.add_done_callback(callBck)
        else:
            return task.result()

    def _stop(self):
        self._loop.stop()
        self._starting = False

    def stop(self):
        """
        runTask: 执行完后后才能调用，可再回调中调用
        调用完记得关闭
        """
        self._loop.call_soon_threadsafe(self._stop)

    def close(self):
        self._loop.call_soon_threadsafe(self._loop.close)
        self._isCallClose = True

    def __del__(self):
        if not self._isCallClose:
            self._loop.close()
