package org.jeecg.modules.app.service.impl;

import cn.binarywang.wx.miniapp.api.WxMaService;
import cn.binarywang.wx.miniapp.bean.WxMaJscode2SessionResult;
import cn.binarywang.wx.miniapp.util.WxMaConfigHolder;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import lombok.extern.log4j.Log4j2;
import me.chanjar.weixin.common.error.WxErrorException;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.mgt.SecurityManager;
import org.apache.shiro.subject.Subject;
import org.jeecg.common.constant.CommonConstant;
import org.jeecg.common.exception.JeecgBootException;
import org.jeecg.common.system.util.JwtUtil;
import org.jeecg.common.system.vo.LoginUser;
import org.jeecg.common.util.RedisUtil;
import org.jeecg.common.util.oConvertUtils;
import org.jeecg.config.shiro.JwtToken;
import org.jeecg.modules.app.service.IUserService;
import org.jeecg.modules.app.vo.LoginUserVO;
import org.jeecg.modules.app.vo.MsgInfoVO;
import org.jeecg.modules.app.vo.MsgVO;
import org.jeecg.modules.system.app.entity.FamilyMembers;
import org.jeecg.modules.system.app.mapper.FamilyMembersMapper;
import org.jeecg.modules.system.entity.*;
import org.jeecg.modules.system.mapper.*;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.List;
import java.util.UUID;

import static org.jeecg.common.constant.CommonConstant.SC_INTERNAL_SERVER_ERROR_500;

@Service
@Log4j2
public class UserServiceImpl implements IUserService {
    @Resource
    private WxMaService wxMaService;
    @Resource
    private SysUserMapper sysUserMapper;
    @Resource
    private SysAnnouncementSendMapper sysAnnouncementSendMapper;
    @Resource
    private SysAnnouncementMapper sysAnnouncementMapper;
    @Resource
    private SysDepartMapper sysDepartMapper;
    @Resource
    private SysUserDepartMapper sysUserDepartMapper;
    @Resource
    private FamilyMembersMapper familyMembersMapper;
    @Resource
    private SecurityManager securityManager;
    @Resource
    private RedisUtil redisUtil;

    @Override
    public LoginUserVO wechatLogin(String code) {
        try {
            WxMaJscode2SessionResult session = wxMaService.getUserService().getSessionInfo(code);
            String openid = session.getOpenid();
            // 通过openId获取在系统中是否是已经绑定过的用户
            SysUser user = sysUserMapper.selectOne(Wrappers.<SysUser>lambdaQuery()
                    .eq(SysUser::getOpenid, openid)
                    .eq(SysUser::getDelFlag, 0));
            if (null == user) {

                // 用户不存在则创建
                    user = new SysUser()
                            .setOpenid(openid)
                            .setPassword(openid)
                            .setStatus(1)
                            .setDelFlag(0)
                            .setUserIdentity(3)
                            .setSalt(oConvertUtils.randomGen(8))
                            .setCreateBy("admin")
                            .setRealname("微信用户")
                            .setUsername("微信用户_" + UUID.randomUUID());
                boolean result = sysUserMapper.insert(user) > 0;
                    if (!result) {
                        throw new JeecgBootException("登录失败", SC_INTERNAL_SERVER_ERROR_500);
                }
                familyMembersMapper.insert(new FamilyMembers().setDelFlag(0).setUserId(user.getId()).setUserType(0).setRealNameStatus(0));
            }
            return generateLoginUserVO(user);
        } catch (WxErrorException e) {
            log.error("微信登录失败: {}", e.getMessage());
            throw new JeecgBootException("小程序登录失败:" + e, SC_INTERNAL_SERVER_ERROR_500);
        } finally {
            WxMaConfigHolder.remove(); // 清理ThreadLocal
        }
    }

    @Override
    public List<MsgVO> getMsg() {
        LoginUser user = (LoginUser) SecurityUtils.getSubject().getPrincipal();
        List<MsgVO> msgVOList = new ArrayList<>();
        if(null != user){
            sysAnnouncementSendMapper.selectList(Wrappers.<SysAnnouncementSend>lambdaQuery()
                    .eq(SysAnnouncementSend::getUserId, user.getId())).forEach(sysAnnouncementSend -> {
                SysAnnouncement sysAnnouncement = sysAnnouncementMapper.selectById(sysAnnouncementSend.getAnntId());
                MsgVO msgVO = new MsgVO()
                        .setReadFlag(sysAnnouncementSend.getReadFlag())
                        .setTitile(sysAnnouncement.getTitile())
                        .setId(sysAnnouncement.getId())
                        .setSendTime(sysAnnouncement.getSendTime())
                        .setImgUrl(sysAnnouncement.getImgUrl()).setSender(sysAnnouncement.getSender());
                msgVOList.add(msgVO);
            });
            return msgVOList;
        }
        return msgVOList;
    }

    @Override
    public MsgInfoVO getMsgInfo(String id) {
        SysAnnouncement sysAnnouncement = sysAnnouncementMapper.selectById(id);
        MsgInfoVO msgInfoVO = new MsgInfoVO();
        BeanUtils.copyProperties(sysAnnouncement, msgInfoVO);
        return msgInfoVO;
    }

    @Override
    @Transactional
    public boolean updateUserInfo(String nickName, String avatarUrl) {
        LoginUser user = (LoginUser) SecurityUtils.getSubject().getPrincipal();
        if(null != nickName && !nickName.isEmpty()){
            sysUserMapper.update(null,Wrappers.<SysUser>lambdaUpdate()
                    .eq(SysUser::getId, user.getId())
                    .set(SysUser::getRealname, nickName));
        }else if(null != avatarUrl && !avatarUrl.isEmpty()){
            sysUserMapper.update(null,Wrappers.<SysUser>lambdaUpdate()
                    .eq(SysUser::getId, user.getId())
                    .set(SysUser::getAvatar, avatarUrl));
        }
        return true;
    }

    @Override
    public LoginUserVO getUserInfo() {
        LoginUser user = (LoginUser) SecurityUtils.getSubject().getPrincipal();
        SysUser sysUser = sysUserMapper.selectById(user.getId());
        return new LoginUserVO()
                .setId(sysUser.getId())
                .setUserName(sysUser.getRealname())
                .setUserAvatar(sysUser.getAvatar())
                .setToken(JwtUtil.sign(sysUser.getUsername(), sysUser.getPassword()));
    }


    private LoginUserVO generateLoginUserVO(SysUser user) {
        String token = JwtUtil.sign(user.getUsername(), user.getPassword());
        // 设置token缓存有效时间
        redisUtil.set(CommonConstant.PREFIX_USER_TOKEN + token, token);
        redisUtil.expire(CommonConstant.PREFIX_USER_TOKEN + token, JwtUtil.EXPIRE_TIME * 2 / 1000);
        // 创建 JwtToken 并登录 Subject
        JwtToken jwtToken = new JwtToken(token);
        Subject subject = new Subject.Builder(securityManager).buildSubject();
        subject.login(jwtToken); // 触发 Shiro 登录流程
        // 确保 LoginUser 可被后续获取
        LoginUser loginUser = new LoginUser();
        BeanUtils.copyProperties(user,loginUser);
        return new LoginUserVO()
                .setToken(token)
                .setId(user.getId())
                .setUserName(user.getUsername())
                .setUserAvatar(user.getAvatar());
    }
}