# encoding:utf-8

import json
import os
from bridge.bridge import Bridge
from bridge.context import ContextType
from bridge.reply import Reply, ReplyType
import plugins
from plugins import *
from common.log import logger


class RolePlay():
    def __init__(self, bot, sessionid, desc, wrapper=None):
        self.bot = bot
        self.sessionid = sessionid
        bot.sessions.clear_session(sessionid)
        bot.sessions.build_session(sessionid, desc)
        self.wrapper = wrapper or "%s"  # 用于包装用户输入

    def reset(self):
        self.bot.sessions.clear_session(self.sessionid)

    def action(self, user_action):
        prompt = self.wrapper % user_action
        return prompt

@plugins.register(name="Role", desc="为你的Bot设置预设角色", version="1.0", author="lanvent", desire_priority= 0)
class Role(Plugin):
    def __init__(self):
        super().__init__()
        curdir = os.path.dirname(__file__)
        config_path = os.path.join(curdir, "roles.json")
        try:
            with open(config_path, "r", encoding="utf-8") as f:
                config = json.load(f)
                self.roles = {role["title"].lower(): role for role in config["roles"]}
            if len(self.roles) == 0:
                raise Exception("no role found")
            self.handlers[Event.ON_HANDLE_CONTEXT] = self.on_handle_context
            self.roleplays = {}
            logger.info("[Role] inited")
        except FileNotFoundError:
            logger.error(f"[Role] init failed, {config_path} not found")
        except Exception as e:
            logger.error("[Role] init failed, exception: %s" % e)

    def get_role(self, name, find_closest=True):
        name = name.lower()
        found_role = None
        if name in self.roles:
            found_role = name
        elif find_closest:
            import difflib

            def str_simularity(a, b):
                return difflib.SequenceMatcher(None, a, b).ratio()
            max_sim = 0.0
            max_role = None
            for role in self.roles:
                sim = str_simularity(name, role)
                if sim >= max_sim:
                    max_sim = sim
                    max_role = role
            found_role = max_role
        return found_role

    def on_handle_context(self, e_context: EventContext):

        if e_context['context'].type != ContextType.TEXT:
            return
        bottype = Bridge().get_bot_type("chat")
        if bottype != "chatGPT":
            return
        bot = Bridge().get_bot("chat")
        content = e_context['context'].content[:]
        clist = e_context['context'].content.split(maxsplit=1)
        desckey = None
        sessionid = e_context['context']['session_id']
        if clist[0] == "$停止扮演":
            if sessionid in self.roleplays:
                self.roleplays[sessionid].reset()
                del self.roleplays[sessionid]
            reply = Reply(ReplyType.INFO, "角色扮演结束!")
            e_context['reply'] = reply
            e_context.action = EventAction.BREAK_PASS
            return
        elif clist[0] == "$角色":
            desckey = "descn"
        elif clist[0].lower() == "$role":
            desckey = "description"
        elif sessionid not in self.roleplays:
            return
        logger.debug("[Role] on_handle_context. content: %s" % content)
        if desckey is not None:
            if len(clist) == 1 or (len(clist) > 1 and clist[1].lower() in ["help", "帮助"]):
                reply = Reply(ReplyType.INFO, self.get_help_text())
                e_context['reply'] = reply
                e_context.action = EventAction.BREAK_PASS
                return
            role = self.get_role(clist[1])
            if role is None:
                reply = Reply(ReplyType.ERROR, "角色不存在")
                e_context['reply'] = reply
                e_context.action = EventAction.BREAK_PASS
                return
            else:
                self.roleplays[sessionid] = RolePlay(bot, sessionid, self.roles[role][desckey],self.roles[role].get("wrapper","%s"))
                reply = Reply(ReplyType.INFO, f"角色设定为 {role} :\n"+self.roles[role][desckey])
                e_context['reply'] = reply
                e_context.action = EventAction.BREAK_PASS
        else:
            prompt = self.roleplays[sessionid].action(content)
            e_context['context'].type = ContextType.TEXT
            e_context['context'].content = prompt
            e_context.action = EventAction.CONTINUE

    def get_help_text(self):
        help_text = "输入\"$角色 (角色名)\"或\"$role (角色名)\"为我设定角色吧,#reset 可以清除设定的角色。\n目前可用角色列表:\n"
        for role in self.roles:
            help_text += f"[{role}]: {self.roles[role]['remark']}\n"
        return help_text