# 导入必要的模块
import logging
import os
import re

import jsonpickle  # 用于对象序列化
from django.conf import settings
from werobot import WeRoBot  # 微信机器人框架
from werobot.replies import ArticlesReply, Article  # 微信图文回复
from werobot.session.filestorage import FileStorage  # 文件会话存储

from djangoblog.utils import get_sha256  # 加密工具函数
from servermanager.api.blogapi import BlogApi  # 博客API
from servermanager.api.commonapi import ChatGPT, CommandHandler  # 聊天和命令处理
from .MemcacheStorage import MemcacheStorage  # 自定义缓存存储

# 初始化微信机器人，从环境变量获取token，默认使用'lylinux'
robot = WeRoBot(token=os.environ.get('DJANGO_WEROBOT_TOKEN') or 'lylinux', enable_session=True)

# 初始化Memcached会话存储
memstorage = MemcacheStorage()
# 检查Memcached是否可用，如果可用则使用，否则使用文件存储
if memstorage.is_available:
    robot.config['SESSION_STORAGE'] = memstorage
else:
    # 如果存在旧的会话文件则删除
    if os.path.exists(os.path.join(settings.BASE_DIR, 'werobot_session')):
        os.remove(os.path.join(settings.BASE_DIR, 'werobot_session'))
    robot.config['SESSION_STORAGE'] = FileStorage(filename='werobot_session')

# 初始化API处理器
blogapi = BlogApi()
cmd_handler = CommandHandler()
logger = logging.getLogger(__name__)


def convert_to_article_reply(articles, message):
    """
    将文章列表转换为微信图文回复格式
    
    Args:
        articles: 文章对象列表
        message: 微信消息对象
        
    Returns:
        ArticlesReply: 图文回复对象
    """
    reply = ArticlesReply(message=message)
    from blog.templatetags.blog_tags import truncatechars_content  # 导入内容截断过滤器
    
    for post in articles:
        # 使用正则表达式从文章内容中提取第一张图片
        imgs = re.findall(r'(?:http\:|https\:)?\/\/.*\.(?:png|jpg)', post.body)
        imgurl = ''
        if imgs:
            imgurl = imgs[0]  # 使用第一张图片作为封面
            
        # 创建图文消息条目
        article = Article(
            title=post.title,  # 文章标题
            description=truncatechars_content(post.body),  # 截断后的文章内容作为描述
            img=imgurl,  # 封面图片URL
            url=post.get_full_url()  # 文章完整URL
        )
        reply.add_article(article)
    return reply


@robot.filter(re.compile(r"^\?.*"))
def search(message, session):
    """
    文章搜索功能
    触发方式: ?关键字
    例如: ?python
    """
    s = message.content
    searchstr = str(s).replace('?', '')  # 移除问号获取搜索关键词
    result = blogapi.search_articles(searchstr)  # 调用搜索API
    
    if result:
        # 将搜索结果转换为文章对象列表
        articles = list(map(lambda x: x.object, result))
        reply = convert_to_article_reply(articles, message)
        return reply
    else:
        return '没有找到相关文章。'


@robot.filter(re.compile(r'^category\s*$', re.I))
def category(message, session):
    """
    获取所有文章分类
    触发方式: category
    """
    categorys = blogapi.get_category_lists()
    content = ','.join(map(lambda x: x.name, categorys))
    return '所有文章分类目录：' + content


@robot.filter(re.compile(r'^recent\s*$', re.I))
def recents(message, session):
    """
    获取最新文章
    触发方式: recent
    """
    articles = blogapi.get_recent_articles()
    if articles:
        reply = convert_to_article_reply(articles, message)
        return reply
    else:
        return "暂时还没有文章"


@robot.filter(re.compile('^help$', re.I))
def help(message, session):
    """
    获取帮助信息
    触发方式: help
    """
    return '''欢迎关注!
            默认会与图灵机器人聊天~~
        你可以通过下面这些命令来获得信息
        ?关键字搜索文章.
        如?python.
        category获得文章分类目录及文章数.
        category-***获得该分类目录文章
        如category-python
        recent获得最新文章
        help获得帮助.
        weather:获得天气
        如weather:西安
        idcard:获得身份证信息
        如idcard:61048119xxxxxxxxxx
        music:音乐搜索
        如music:阴天快乐
        PS:以上标点符号都不支持中文标点~~
        '''


@robot.filter(re.compile(r'^weather\:.*$', re.I))
def weather(message, session):
    """天气查询功能（建设中）"""
    return "建设中..."


@robot.filter(re.compile(r'^idcard\:.*$', re.I))
def idcard(message, session):
    """身份证查询功能（建设中）"""
    return "建设中..."


@robot.handler
def echo(message, session):
    """
    默认消息处理器
    处理所有未匹配到其他过滤器的消息
    """
    handler = MessageHandler(message, session)
    return handler.handler()


class MessageHandler:
    """消息处理器类，负责处理用户会话和权限验证"""
    
    def __init__(self, message, session):
        userid = message.source
        self.message = message
        self.session = session
        self.userid = userid
        try:
            # 从会话中获取用户信息
            info = session[userid]
            self.userinfo = jsonpickle.decode(info)
        except Exception as e:
            # 如果会话中没有用户信息，创建新的用户信息对象
            userinfo = WxUserInfo()
            self.userinfo = userinfo

    @property
    def is_admin(self):
        """检查用户是否为管理员"""
        return self.userinfo.isAdmin

    @property
    def is_password_set(self):
        """检查管理员密码是否已设置"""
        return self.userinfo.isPasswordSet

    def save_session(self):
        """保存用户信息到会话"""
        info = jsonpickle.encode(self.userinfo)
        self.session[self.userid] = info

    def handler(self):
        """主消息处理方法"""
        info = self.message.content

        # 管理员退出命令
        if self.userinfo.isAdmin and info.upper() == 'EXIT':
            self.userinfo = WxUserInfo()
            self.save_session()
            return "退出成功"
            
        # 进入管理员模式
        if info.upper() == 'ADMIN':
            self.userinfo.isAdmin = True
            self.save_session()
            return "输入管理员密码"
            
        # 管理员密码验证
        if self.userinfo.isAdmin and not self.userinfo.isPasswordSet:
            passwd = settings.WXADMIN  # 从设置获取管理员密码
            if settings.TESTING:  # 测试环境下使用简单密码
                passwd = '123'
            # 验证密码（双重SHA256加密）
            if passwd.upper() == get_sha256(get_sha256(info)).upper():
                self.userinfo.isPasswordSet = True
                self.save_session()
                return "验证通过,请输入命令或者要执行的命令代码:输入helpme获得帮助"
            else:
                # 密码错误次数限制
                if self.userinfo.Count >= 3:
                    self.userinfo = WxUserInfo()
                    self.save_session()
                    return "超过验证次数"
                self.userinfo.Count += 1
                self.save_session()
                return "验证失败，请重新输入管理员密码:"
                
        # 管理员命令执行
        if self.userinfo.isAdmin and self.userinfo.isPasswordSet:
            # 确认执行命令
            if self.userinfo.Command != '' and info.upper() == 'Y':
                return cmd_handler.run(self.userinfo.Command)
            else:
                # 获取命令帮助
                if info.upper() == 'HELPME':
                    return cmd_handler.get_help()
                # 保存命令等待确认
                self.userinfo.Command = info
                self.save_session()
                return "确认执行: " + info + " 命令?"

        # 默认使用ChatGPT回复
        return ChatGPT.chat(info)


class WxUserInfo():
    """微信用户信息类，用于存储用户会话状态"""
    
    def __init__(self):
        self.isAdmin = False  # 是否为管理员
        self.isPasswordSet = False  # 是否通过密码验证
        self.Count = 0  # 密码尝试次数
        self.Command = ''  # 待确认的命令