
from asyncio import sleep
from enum import Enum
import importlib
from mimetypes import MimeTypes
import os
from typing import AsyncGenerator, List

from xbridge import file
from xbridge.MyInfo import MyInfo
from xbridge.config import Config
from xbridge.transmsg import  Codable, NormalMsg, MsgType, ParamRequire, ParamSelection, ParamType


class AvailableActions:
    SendFiles = 'send_files'
    GetFiles = 'get_files'
    ListFiles = 'list_files'
    GetInfo = 'info'
    Trust = 'trust'
    GetActions = "get_actions"
    
    # for test
    Echo = "echo"


async def handle_list_actions(msg: NormalMsg, received_files: List[str]) -> AsyncGenerator[NormalMsg, None]:

    actions = [
        ParamSelection(AvailableActions.GetFiles, "Get Files"),
        ParamSelection(AvailableActions.SendFiles, "Send Files"),
        ParamSelection(AvailableActions.ListFiles, "Get Files List"),
    ]

    for item in os.listdir(Config.config_dir):
        if item.endswith(".py"):
            actions.append(ParamSelection(item.removesuffix(".py")))


    yield NormalMsg(MsgType.Reply, action=msg.action, requires=[
        ParamRequire("", ParamType.SelectableList, "可用的操作", selections=actions)
    ])

    # print("actions", actions)
    # yield NormalMsg(MsgType.Reply, msg.app, msg.action, params=actions)


#
# client request get file list from me
#
# list <path>
#
async def handle_list_files(msg: NormalMsg, received_files: List[str]) -> AsyncGenerator[NormalMsg, None]:
    files = []
    p = ''
    params = msg.params
    if params is not None and len(params) > 0:
        p = params[0]
    dir = os.path.join(Config.files_dir, p)

    for item in os.listdir(dir):
        files.append(os.path.join(p, item))

    # await sleep(60)

    yield NormalMsg(MsgType.Reply, None, msg.app, msg.action, files)


async def handle_echo(msg: NormalMsg, received_files: List[str]) -> AsyncGenerator[NormalMsg, None]:
    
    # if msg.params is None or len(msg.params) == 0:
    #     # params error, reply param requirements
    #     print("echo: params is invalid! reply requirements")
    #     # require: ParamRequire = 
    #     yield NormalMsg(MsgType.Reply, action=msg.action, requires=[
    #         ParamRequire("", ParamType.SelectableList, "想要取得的文件", selections=[
    #             ParamSelection(select="a.txt"),
    #             ParamSelection(select="b.txt"),
    #         ])
    #     ])
    #     return

    yield NormalMsg(MsgType.Reply, None, msg.app, msg.action, files=received_files)



#
# otherside request get files/dirs from me
#
# get <file_path_on_otherside>...
#
async def handle_get_files(msg: NormalMsg, received_files: List[str]) -> AsyncGenerator[NormalMsg, None]:
    
    if msg.params is None or len(msg.params) == 0:
        # params error, reply param requirements
        print("get_files: params is invalid! reply requirements")
        # require: ParamRequire = 
        yield NormalMsg(MsgType.Reply, action=msg.action, requires=[
            ParamRequire("", ParamType.SelectableList, "想要取得的文件", selections=[
                ParamSelection(select="a.txt"),
                ParamSelection(select="b.txt"),
            ])
        ])
        return

    yield NormalMsg(MsgType.Reply, None, msg.app, msg.action, files=msg.params)



#
# otherside request send files to me
#
# send <file_path_on_otherside>...
#
async def handle_sendfiles(msg: NormalMsg, received_files: List[str]) -> AsyncGenerator[NormalMsg, None]:

    if msg.params is None or len(msg.params) == 0:
        # params error, reply param requirements
        print("send_files: params is invalid! reply requirements")
        # require: ParamRequire = 
        yield NormalMsg(MsgType.Reply, action=msg.action, requires=[
            ParamRequire("", ParamType.FileOrDirList, "待发送的文件")
        ])
        return

    # save received files to files dir
    file.save_files(received_files)

    yield NormalMsg(MsgType.Reply, None, msg.app, msg.action)


async def handle_get_info(msg: NormalMsg, received_files: List[str]) -> AsyncGenerator[NormalMsg, None]:

    # load my info
    info = MyInfo(os.path.join(Config.config_dir, "info.json"))

    if len(msg.params) > 0 and msg.params[0] == info.version:
        yield NormalMsg(MsgType.Reply, None, msg.app, msg.action, params=[info.version])
        return
           
    # reply result
    # head_img = "data:image/webp;base64, "
    yield NormalMsg(MsgType.Reply, None, msg.app, msg.action, params=[info.version, info.name, info.avatar_url])


# request: trust with params[<code>]
# reply: params[1]
#           "passcode_required" if no code provided
#           "accepted" if code is correct
#           "refused" if code if incorrect 
#
async def handle_trust(msg: NormalMsg, received_files: List[str]) -> AsyncGenerator[NormalMsg, None]:
    reply = "refused"
    if len(msg.params) > 0:
        if msg.params[0] == "0000":
            reply = "accepted"
    else:
        reply = "passcode_required"
    yield NormalMsg(MsgType.Reply, None, msg.app, msg.action, params=[reply])



def get_handler_func(action: str):
        # find an handler to handle the request
        handle = None
        # print("config dir=", Config.config_dir)
        module_file_path = os.path.join(Config.config_dir, "scripts", action + '.py')
        module_name = action
        if not os.path.isfile(module_file_path):
            if Config.files_dir != '':
                # intergrated action handlers
                if action == AvailableActions.GetFiles:
                    handle = handle_get_files
                elif action == AvailableActions.SendFiles:
                    handle = handle_sendfiles
                elif action == AvailableActions.ListFiles:
                    handle = handle_list_files
                elif action == AvailableActions.GetInfo:
                    handle = handle_get_info
                elif action == AvailableActions.Trust:
                    handle = handle_trust
                elif action == AvailableActions.Echo:
                    handle = handle_echo
                elif action == AvailableActions.GetActions:
                    handle = handle_list_actions
        else:
            # custom action handlers
            print("load %s from %s" % (module_name, module_file_path))
            module_spec = importlib.util.spec_from_file_location(
                module_name, module_file_path)
            module = importlib.util.module_from_spec(module_spec)
            module_spec.loader.exec_module(module)
            handle = module.handle_action
        return handle