package com.seer.teach.user.app.user.service;

import cn.dev33.satoken.stp.StpUtil;
import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.json.JSONUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.seer.teach.common.dto.mq.im.MqUserInfoDTO;
import com.seer.teach.common.entity.CityEntity;
import com.seer.teach.common.entity.ProvinceEntity;
import com.seer.teach.common.enums.*;
import com.seer.teach.common.enums.im.ImMqTopicEnum;
import com.seer.teach.common.enums.im.UserInfoTopiTagEnum;
import com.seer.teach.common.service.RegionAddressService;
import com.seer.teach.common.utils.AssertUtils;
import com.seer.teach.common.utils.CommonUtils;
import com.seer.teach.iot.api.DeviceInfoServiceApi;
import com.seer.teach.iot.api.UserDeviceServiceApi;
import com.seer.teach.iot.api.req.DeviceReqDTO;
import com.seer.teach.iot.api.req.UserDeviceReqDTO;
import com.seer.teach.iot.api.resp.DeviceRespDTO;
import com.seer.teach.iot.api.resp.UserDeviceRespDTO;
import com.seer.teach.pay.api.wallet.CoinAccountServiceApi;
import com.seer.teach.pay.api.wallet.dto.UserCoinAccountRespDTO;
import com.seer.teach.user.app.convert.UserAuthConvert;
import com.seer.teach.user.app.convert.UserInfoConvert;
import com.seer.teach.user.app.user.controller.req.ChildrenInfoUpdateReq;
import com.seer.teach.user.app.user.controller.req.UserRegisterReq;
import com.seer.teach.user.app.user.controller.req.UserResetPasswordReq;
import com.seer.teach.user.app.user.controller.resp.AppUserInfoResp;
import com.seer.teach.user.entity.*;
import com.seer.teach.user.mq.MqProducer;
import com.seer.teach.user.service.*;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;

import jakarta.annotation.Resource;
import java.util.*;
import java.util.stream.Collectors;

@Slf4j
@Service
public class AppMyChildrenService {


    @Value("${zs.user.login.check-device-bind-app.enabled:true}")
    private boolean isCheckDeviceBindApp;

    @Resource
    private IUserService userService;

    @Resource
    private IUserRelationService userRelationService;

    @Resource
    private IUserExtendService userExtendService;

    @Resource
    private IUserRoleService userRoleService;

    @Resource
    private ILevelService levelService;

    @Resource
    private IGradeService gradeService;

    @Resource
    private MqProducer mqProducer;

    @Resource
    private CoinAccountServiceApi coinAccountServiceApi;

    @Resource
    private DeviceInfoServiceApi deviceInfoServiceApi;

    @Resource
    private UserDeviceServiceApi userDeviceServiceApi;

    @Resource
    private RegionAddressService regionAddressService;

    @Resource
    private IUserFamilyService userFamilyService;

    /**
     * 用户注册孩子账号
     *
     * @param userRegisterReq 注册参数
     */
    @Transactional(rollbackFor = Exception.class, timeout = 120)
    public boolean registerChildren(String device, UserRegisterReq userRegisterReq) {
        int userId = StpUtil.getLoginIdAsInt();
        log.info("用户 userId:[{}]注册 孩子", userId);
        UserEntity userEntity = userService.getOneByMobile(userRegisterReq.getMobile());
        AssertUtils.isNull(userEntity, ResultCodeEnum.USER_MOBILE_EXIST);

        UserEntity child = UserAuthConvert.INSTANCE.convertOneToEntity(userRegisterReq);
        child.setPassword(CommonUtils.encryptPassword(child.getPassword()));
        //保存孩子信息
        boolean saved = userService.save(child);
        log.info("用户 userId:[{}]注册 孩子 保存结果:[{}]", userId, saved);

        LevelEntity startLevel = levelService.getOne(new LambdaQueryWrapper<LevelEntity>()
                .eq(LevelEntity::getSort, 1));

        // 保存孩子扩展信息
        UserExtendEntity userExtendEntity = saveChildExtend(child.getId(), userRegisterReq.getGradeId(), startLevel.getId());

        // 创建家庭
        Integer familyId = createUserFamilyIfNotExists(userId, child.getNickName());

        // 保存孩子关系
        saveUserRelation(userId, child, familyId);

        // 为孩子分配角色
        userRoleService.assignUserRoleByRoleCode(child.getId(), RoleEnum.CHILDREN.getCode());

        if (isCheckDeviceBindApp) {
            DeviceRespDTO deviceResult = deviceInfoServiceApi.getDevice(device);
            log.info("根据设备标识[{}]查询的设备信息：{}", device, deviceResult);

            AssertUtils.notNull(deviceResult, ResultCodeEnum.DEVICE_NOT_FOUND);

            UserDeviceRespDTO userDeviceRespDTO = userDeviceServiceApi.getUserDeviceByDeviceId(deviceResult.getId());
            AssertUtils.isNull(userDeviceRespDTO, ResultCodeEnum.DEVICE_IS_BIND);

            // 为孩子绑定设备
            UserDeviceReqDTO userDevice = new UserDeviceReqDTO();
            userDevice.setUserId(child.getId());
            userDevice.setDeviceId(deviceResult.getId());
            userDeviceServiceApi.save(userDevice);
            UserCoinAccountRespDTO userAccount = coinAccountServiceApi.getUserCoinAccount(userId);
            log.info("用户[{}]绑定设备[{}]成功", child.getId(), deviceResult.getId());
            publishMsg(child, userExtendEntity, userRegisterReq.getGradeId(), startLevel, device, userAccount);
        }
        return true;
    }

    private Integer createUserFamilyIfNotExists(Integer userId, String nickName) {
        List<UserRelationEntity> userRelations = userRelationService.getUserRelationByUserIdAndType(userId, UserRelationEnum.PARENT_CHILD);
        if (CollectionUtils.isEmpty(userRelations)) {
            return saveUserFamily(userId, nickName);
        }
        Integer familyId = userRelations.stream().findFirst().get().getFamilyId();
        log.info("用户 userId:[{}]注册 孩子 获取家庭Id:[{}]", userId, familyId);
        if (Objects.nonNull(familyId)) {
            return familyId;
        }
        return saveUserFamily(userId, nickName);
    }

    private Integer saveUserFamily(Integer userId, String nickName) {
        UserFamilyEntity useFamily = new UserFamilyEntity();
        useFamily.setName(nickName + "的家庭");
        useFamily.setPrimaryGuardianUserId(userId);
        boolean saveUserFamilyResult = userFamilyService.save(useFamily);
        log.info("用户 userId:[{}]注册 孩子 创建家庭结果:[{}]", userId, saveUserFamilyResult);
        return useFamily.getId();
    }

    private UserExtendEntity saveChildExtend(Integer childId, Integer gradeId, Integer levelId) {
        UserExtendEntity userExtendEntity = new UserExtendEntity();
        userExtendEntity.setUserId(childId);
        userExtendEntity.setGradeId(gradeId);
        userExtendEntity.setLevelId(levelId);
        userExtendEntity.setExperience(0);
        boolean userExtendSaved = userExtendService.save(userExtendEntity);
        log.info("用户注册孩子扩展信息保存结果:[{}]", userExtendSaved);
        return userExtendEntity;
    }

    private void saveUserRelation(int userId, UserEntity child, Integer familyId) {
        List<UserRelationEntity> userRelationEntities = userRelationService.getUserRelationsByFamilyIdAndType(familyId, UserRelationEnum.PARENT_CHILD);
        if (CollectionUtils.isEmpty(userRelationEntities)) {
            UserRelationEntity defaultUserRelation = userRelationService.getDefaultUserRelationByUserId(userId);
            UserRelationEntity userRelationEntity = new UserRelationEntity();
            userRelationEntity.setUserId(userId);
            userRelationEntity.setRelationId(child.getId());
            userRelationEntity.setFamilyId(familyId);
            userRelationEntity.setType(UserRelationEnum.PARENT_CHILD.getCode());
            userRelationEntity.setIsDefault(Objects.nonNull(defaultUserRelation) ? UserRelationEntity.IS_NOT_DEFAULT : UserRelationEntity.IS_DEFAULT);
            boolean userRelationSaved = userRelationService.save(userRelationEntity);
            log.info("用户 userId:[{}]注册 孩子关系保存结果:[{}]", userId, userRelationSaved);
            return;
        }
        Set<Integer> parentUserIds = userRelationEntities.stream().map(UserRelationEntity::getUserId).collect(Collectors.toSet());
        List<UserRelationEntity> newRelations = new ArrayList<>();
        parentUserIds.forEach(parentUserId -> {
            UserRelationEntity newRelation = new UserRelationEntity();
            newRelation.setUserId(parentUserId);
            newRelation.setRelationId(child.getId());
            newRelation.setFamilyId(familyId);
            newRelation.setType(UserRelationEnum.PARENT_CHILD.getCode());
            newRelation.setIsDefault(UserRelationEntity.IS_NOT_DEFAULT);
            newRelations.add(newRelation);
        });
        boolean saveBatch = userRelationService.saveBatch(newRelations);
        log.info("用户 userId:[{}]注册 孩子关系保存结果:[{}]", userId, saveBatch);
    }

    /**
     * 重置孩子密码
     *
     * @param resetPasswordReq 重置密码参数
     * @return boolean true表示成功，反之false
     */
    public boolean resetPassword(UserResetPasswordReq resetPasswordReq) {
        Integer userId = StpUtil.getLoginIdAsInt();

        UserRelationEntity userRelation = userRelationService.getUserRelationByUserIdAndRelationId(userId, resetPasswordReq.getChildId(), UserRelationEnum.PARENT_CHILD);

        AssertUtils.notNull(userRelation, ResultCodeEnum.NOT_BIND_CHILDREN);

        Integer childrenId = userRelation.getRelationId();
        log.info("用户[{}]重置孩子[{}]密码", userId, childrenId);

        UserEntity children = userService.getById(childrenId);
        children.setPassword(CommonUtils.encryptPassword(resetPasswordReq.getPassword()));
        boolean updated = userService.updateById(children);
        log.info("用户[{}]重置孩子[{}]密码结果[{}]", userId, childrenId, updated);
        return updated;
    }


    /**
     * 获取默认孩子信息
     *
     * @return AppUserInfoResp
     */
    public AppUserInfoResp getDefaultChildrenInfo() {
        Integer userId = StpUtil.getLoginIdAsInt();
        log.info("getDefaultChildrenInfo 获取用户信息,登录用户:{}", userId);
        UserRelationEntity userRelation = userRelationService.getDefaultUserRelationByUserId(userId);

        AssertUtils.notNull(userRelation, ResultCodeEnum.NOT_BIND_CHILDREN);

        Integer childrenId = userRelation.getRelationId();
        log.info("用户[{}]获取孩子[{}]信息", userId, childrenId);
        return this.getChildDetail(childrenId);
    }


    /**
     * 获取孩子详情
     *
     * @param childId
     * @return
     */
    public AppUserInfoResp getChildDetail(Integer childId) {
        UserEntity child = userService.checkUserExistsByUserId(childId);

        UserExtendEntity userExtendEntity = userExtendService.getUserExtendByUserId(childId);

        LevelEntity level = levelService.getById(userExtendEntity.getLevelId());

        DeviceRespDTO device = userDeviceServiceApi.getDeviceDTOByUserId(childId);

        ProvinceEntity province = regionAddressService.getProvinceByCityId(device.getCityId());
        CityEntity city = regionAddressService.getCityById(device.getCityId());

        return UserInfoConvert.INSTANCE.toUserInfoResp(child, userExtendEntity, level, province, city);
    }

    /**
     * 获取孩子列表
     *
     * @return List<AppUserInfoResp>
     */
    public List<AppUserInfoResp> list() {
        Integer userId = StpUtil.getLoginIdAsInt();
        log.info("获取用户信息,登录用户:{}", userId);
        List<UserRelationEntity> userRelations = userRelationService.getUserRelationsByUserId(userId);
        if (CollectionUtil.isEmpty(userRelations)) {
            return Collections.emptyList();
        }
        Set<Integer> childrenIds = userRelations.stream().map(UserRelationEntity::getRelationId).collect(Collectors.toSet());

        List<UserEntity> users = userService.getListByUserIds(childrenIds);
        if (CollectionUtil.isEmpty(users)) {
            return Collections.emptyList();
        }
        List<UserExtendEntity> userExtends = userExtendService.getListByUserIds(childrenIds);

        List<LevelEntity> userLevels = new ArrayList<>(users.size());
        if (CollectionUtil.isNotEmpty(userExtends)) {
            Set<Integer> levelIds = userExtends.stream().map(UserExtendEntity::getLevelId).collect(Collectors.toSet());
            if (CollectionUtil.isNotEmpty(levelIds)) {
                userLevels.addAll(levelService.getListByLevelIds(levelIds));
            }
        }
        return UserInfoConvert.INSTANCE.toUserInfoListResp(users, userExtends, userLevels);
    }

    /**
     * 设置默认孩子
     *
     * @param childId 孩子id
     * @return boolean true表示成功，反之false
     */
    public boolean setDefaultChild(Integer childId) {
        Integer userId = StpUtil.getLoginIdAsInt();
        log.info("setDefaultChild登录用户:{}", userId);
        boolean updatedDefault = userRelationService.updateDefaultStatusByUserId(userId, UserRelationEntity.IS_NOT_DEFAULT);
        log.info("用户[{}]取消默认孩子[{}]结果[{}]", userId, childId, updatedDefault);
        boolean updated = userRelationService.updateDefaultStatusByUserIdAndRelationId(userId, childId, UserRelationEntity.IS_DEFAULT);
        log.info("用户[{}]设置默认孩子[{}]结果[{}]", userId, childId, updated);
        return updated;
    }

    /**
     * 更新孩子信息
     *
     * @param updateReq 更新孩子信息参数
     * @return boolean true表示成功，反之false
     */
    /*@CacheInvalidate(name = UserInfoCacheService.USER_CACHE_NAME, key = "#updateReq.childId")*/
    @Transactional(rollbackFor = Exception.class, timeout = 120)
    public boolean updateChildrenInfo(ChildrenInfoUpdateReq updateReq) {
        Integer userId = StpUtil.getLoginIdAsInt();
        log.info("用户[{}]更新孩子[{}]信息", userId, updateReq.getChildId());

        UserEntity children = userService.getChildrenByUserId(userId, updateReq.getChildId());
        AssertUtils.notNull(children, ResultCodeEnum.NOT_BIND_CHILDREN);
        Integer childrenId = children.getId();
        log.info("用户[{}]的绑定孩子[{}]", userId, children.getId());
        DeviceRespDTO deviceRespDTO = userDeviceServiceApi.getDeviceDTOByUserId(childrenId);
        log.info("用户[{}]的绑定孩子[{}]设备信息:[{}]", userId, childrenId, deviceRespDTO);

        if (StringUtils.hasText(updateReq.getCity())) {
            CityEntity cityData = regionAddressService.getCityByCityName(updateReq.getCity());
            AssertUtils.notNull(cityData, ResultCodeEnum.CITY_UPDATE_ERROR);
            DeviceReqDTO deviceReqDTO = new DeviceReqDTO();
            deviceReqDTO.setId(deviceRespDTO.getId());
            deviceReqDTO.setCityId(cityData.getId());
            deviceInfoServiceApi.updateDeviceById(deviceReqDTO);
            log.info("更新设备城市信息:{}", deviceReqDTO);
        }

        UserEntity updateUser = UserInfoConvert.INSTANCE.toUserInfoEntity(updateReq);
        updateUser.setId(childrenId);
        log.info("更新用户信息:{}", updateUser);
        boolean updated = userService.updateById(updateUser);
        log.info("更新用户信息:{}", updated);

        UserExtendEntity userExtendEntity = userExtendService.getUserExtendByUserId(childrenId);
        // 更新用户扩展信息中的年纪
        if (Objects.nonNull(updateReq.getGradeId())) {
            UserExtendEntity updateUserExtendEntity = UserInfoConvert.INSTANCE.convertUserExtendOne(updateReq, userExtendEntity.getId(), childrenId);
            boolean updatedUserExtend = userExtendService.updateById(updateUserExtendEntity);
            log.info("更新用户扩展信息:{}的结果：{}", updateUserExtendEntity, updatedUserExtend);
            userExtendEntity.setGradeId(updateReq.getGradeId());
        }
        pushUpdateChildrenInfoMessage(children, deviceRespDTO.getDevice(), childrenId, userExtendEntity);
        return updated;
    }


    private void publishMsg(UserEntity user, UserExtendEntity userExtendEntity, Integer gradeId, LevelEntity level, String device, UserCoinAccountRespDTO userAccount) {
        int userId = user.getId();
        GradeEntity grade = gradeService.getById(gradeId);
        MqUserInfoDTO userInfoDTO = UserInfoConvert.INSTANCE.toMqUserInfoDTO(user, userExtendEntity, grade, level, device);
        userInfoDTO.setExperience(CommonUtils.calculatePercentage(userInfoDTO.getExperience(), level.getPoint()));
        userInfoDTO.setCoinNumber(userAccount.getAvailableBalance().intValue());
        String userJson = JSONUtil.toJsonStr(userInfoDTO);
        String topic = ImMqTopicEnum.USER_INFO.getTopic();
        String tag = UserInfoTopiTagEnum.ACTIVE_SUCCESS_ENTER_TV.getTag();
        log.info("发送登录成功[{}]MQ消息开始 Device: [{}],Topic:{}, Tag:{}", userId, device, topic, tag);
        mqProducer.sendMsg(topic, tag, device, userJson);
        log.info("发送孩子[{}]登录成功的MQ消息成功 Device: [{}]", userId, device);
    }

    private void pushUpdateChildrenInfoMessage(UserEntity children, String device, Integer userId, UserExtendEntity userExtendEntity) {
        GradeEntity grade = gradeService.getById(userExtendEntity.getGradeId());
        LevelEntity level = levelService.getById(userExtendEntity.getLevelId());
        MqUserInfoDTO userInfoDTO = UserInfoConvert.INSTANCE.toMqUserInfoDTO(children, userExtendEntity, grade, level, device);
        userInfoDTO.setExperience(CommonUtils.calculatePercentage(userExtendEntity.getExperience(), level.getPoint()));
        String userJson = JSONUtil.toJsonStr(userInfoDTO);
        String topic = ImMqTopicEnum.USER_INFO.getTopic();
        String tag = UserInfoTopiTagEnum.UPDATE_CHILDREN_INFO.getTag();
        log.info("发送更新孩子[{}]MQ消息开始 Device: [{}],Topic:{}, Tag:{}", userId, device, topic, tag);
        mqProducer.sendMsg(topic, tag, device, userJson);
        log.info("发送更新孩子[{}]MQ消息成功 Device: [{}]", userId, device);
    }

}
