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.SysAnnouncement;
import org.jeecg.modules.system.entity.SysAnnouncementSend;
import org.jeecg.modules.system.entity.SysDepart;
import org.jeecg.modules.system.entity.SysUser;
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.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.*;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.stream.Collectors;

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

@Service
@Log4j2
public class UserServiceImpl implements IUserService {
    private static final ExecutorService executor = Executors.newFixedThreadPool(4);
    @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
    @Transactional
    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(generateRandomString(10,5));
                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
        }
    }
    private String generateRandomString(int letterCount, int digitCount) {
        StringBuilder sb = new StringBuilder();
        String letters = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
        String digits = "0123456789";
        java.util.Random random = new java.util.Random();

        // 生成指定数量的大写字母
        for (int i = 0; i < letterCount; i++) {
            sb.append(letters.charAt(random.nextInt(letters.length())));
        }

        // 生成指定数量的数字
        for (int i = 0; i < digitCount; i++) {
            sb.append(digits.charAt(random.nextInt(digits.length())));
        }

        return sb.toString();
    }
    @Override
    public List<MsgVO> getMsg() {
        LoginUser user = (LoginUser) SecurityUtils.getSubject().getPrincipal();
        List<MsgVO> msgVOList = new ArrayList<>();
        if (null != user) {
            Set<String> uniqueIds = new HashSet<>();
            List<SysAnnouncementSend> announcementSends = sysAnnouncementSendMapper.selectList(Wrappers.<SysAnnouncementSend>lambdaQuery()
                    .eq(SysAnnouncementSend::getUserId, user.getId())
                    .eq(SysAnnouncementSend::getReadFlag, 0));

            List<SysAnnouncementSend> distinctList = announcementSends.stream()
                    .filter(a -> a.getId() != null && uniqueIds.add(a.getId()))
                    .collect(Collectors.toList());
            distinctList.forEach(sysAnnouncementSend -> {
                SysAnnouncement sysAnnouncement =
                        sysAnnouncementMapper.selectOne(Wrappers.lambdaQuery(SysAnnouncement.class).eq(SysAnnouncement::getId,
                                sysAnnouncementSend.getAnntId()).eq(SysAnnouncement::getSendStatus, 1));
                MsgVO msgVO = new MsgVO();
                if(null !=sysAnnouncement){
                    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, String phone) {
        LoginUser user = (LoginUser) SecurityUtils.getSubject().getPrincipal();
        if (null != nickName && !nickName.isEmpty()) {
            sysUserMapper.update(null, Wrappers.<SysUser>lambdaUpdate()
                    .eq(SysUser::getId, user.getId())
                    .set(SysUser::getUsername, nickName));
        } else if (null != avatarUrl && !avatarUrl.isEmpty()) {
            sysUserMapper.update(null, Wrappers.<SysUser>lambdaUpdate()
                    .eq(SysUser::getId, user.getId())
                    .set(SysUser::getAvatar, avatarUrl));
        } else if (null != phone && !phone.isEmpty()) {
            sysUserMapper.update(null, Wrappers.<SysUser>lambdaUpdate()
                    .eq(SysUser::getId, user.getId())
                    .set(SysUser::getPhone, phone));
        }
        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.getUsername())
                .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());
    }
}