package com.gxwebsoft.common.system.service.impl;

import cn.hutool.core.util.DesensitizedUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.gxwebsoft.common.core.exception.BusinessException;
import com.gxwebsoft.common.core.utils.CommonUtil;
import com.gxwebsoft.common.core.web.PageParam;
import com.gxwebsoft.common.core.web.PageResult;
import com.gxwebsoft.common.system.entity.*;
import com.gxwebsoft.common.system.mapper.UserMapper;
import com.gxwebsoft.common.system.param.LoginParam;
import com.gxwebsoft.common.system.param.RoleParam;
import com.gxwebsoft.common.system.param.UserParam;
import com.gxwebsoft.common.mq.producer.SyncMessageProducer;
import com.gxwebsoft.common.system.service.*;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Isolation;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.util.Collections;
import java.util.List;
import java.util.stream.Collectors;

import static com.gxwebsoft.common.core.constants.PlatformConstants.WEB;

/**
 * 用户Service实现
 *
 * @author WebSoft
 * @since 2018-12-24 16:10:14
 */
@Slf4j
@Service
public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements UserService {
    @Resource
    private UserRoleService userRoleService;
    @Resource
    private RoleService roleService;
    @Resource
    private RoleMenuService roleMenuService;
    @Resource
    private BCryptPasswordEncoder bCryptPasswordEncoder;
    @Resource
    private UserService userService;
    @Resource
    private OrganizationService organizationService;
    @Resource
    private UserRefereeService userRefereeService;
    @Resource
    private TenantService tenantService;

    @Autowired(required = false)
    private SyncMessageProducer syncMessageProducer;

    @Override
    public PageResult<User> pageRel(UserParam param) {
        PageParam<User, UserParam> page = new PageParam<>(param);
        page.setDefaultOrder("create_time desc");
        List<User> list = baseMapper.selectPageRel(page, param);
        // 查询用户的角色
        selectUserRoles(list);
        return new PageResult<>(list, page.getTotal());
    }

    @Override
    public List<User> listRel(UserParam param) {
        List<User> list = baseMapper.selectListRel(param);
        // 查询用户的角色
        selectUserRoles(list);
        // 排序
        PageParam<User, UserParam> page = new PageParam<>(param);
        page.setDefaultOrder("create_time desc");
        return page.sortRecords(list);
    }

    @Override
    public User getByIdRel(Integer userId) {
        UserParam param = new UserParam();
        param.setUserId(userId);
        User user = param.getOne(baseMapper.selectListRel(param));
        if (user != null) {
            user.setHasPassword(StrUtil.isNotBlank(user.getPassword()));
            user.setPassword(null);
            user.setRoles(userRoleService.listByUserId(user.getUserId()));
            user.setAuthorities(roleMenuService.listMenuByUserId(user.getUserId(), null));
        }
      return user;
    }

    @Override
    public User getByUsername(String username) {
        return getByUsername(username, null);
    }

    @Override
    public User getByUsername(String username, Integer tenantId) {
        if (StrUtil.isBlank(username)) {
            return null;
        }
        User user = baseMapper.selectByUsername(username, tenantId);
        if (user != null) {
            user.setRoles(userRoleService.listByUserId(user.getUserId()));
            user.setAuthorities(roleMenuService.listMenuByUserId(user.getUserId(), null));
        }
        return user;
    }

    @Override
    public User getByUsernamePhone(String username, Integer tenantId) {
        if (StrUtil.isBlank(username)) {
            return null;
        }
        User user = getOne(new LambdaQueryWrapper<User>()
                .and(wrapper -> wrapper
                        .eq(User::getUsername, username)
                        .or()
                        .eq(User::getPhone, username))
                .eq(tenantId != null, User::getTenantId, tenantId)
                .eq(User::getDeleted, 0)
                .orderByDesc(User::getUserId)
                .last("limit 1")
        );
        if (user != null) {
            user.setRoles(userRoleService.listByUserId(user.getUserId()));
            user.setAuthorities(roleMenuService.listMenuByUserId(user.getUserId(), null));
        }
        return user;
    }

    @Override
    public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
        return getByUsername(username);
    }

    @Transactional(rollbackFor = {Exception.class}, isolation = Isolation.SERIALIZABLE)
    @Override
    public boolean saveUser(User user) {
        if (StrUtil.isNotEmpty(user.getUsername()) && baseMapper.selectCount(new LambdaQueryWrapper<User>()
                .eq(User::getUsername, user.getUsername())) > 0) {
            throw new BusinessException("账号已存在");
        }
        if (StrUtil.isNotEmpty(user.getPhone()) && baseMapper.selectCount(new LambdaQueryWrapper<User>()
                .eq(User::getPhone, user.getPhone())) > 0) {
            throw new BusinessException("手机号已存在");
        }
        if (StrUtil.isNotEmpty(user.getEmail()) && baseMapper.selectCount(new LambdaQueryWrapper<User>()
                .eq(User::getEmail, user.getEmail())) > 0) {
            throw new BusinessException("邮箱已存在");
        }
        boolean result = baseMapper.insert(user) > 0;
        if (result && user.getRoles() != null && user.getRoles().size() > 0) {
            List<Integer> roleIds = user.getRoles().stream().map(Role::getRoleId).collect(Collectors.toList());
            if (userRoleService.saveBatch(user.getUserId(), roleIds) < roleIds.size()) {
                throw new BusinessException("用户角色添加失败");
            }
        }
        // 用户创建成功后，通过MQ异步同步用户数据到 websopy
        if (result && syncMessageProducer != null) {
            User savedUser = getAllByUserId(String.valueOf(user.getUserId()));
            if (savedUser != null) {
                syncMessageProducer.sendUserSyncMessage("websopy", "CREATE", savedUser);
                log.info("用户创建后发送MQ消息同步到websopy: userId={}, phone={}", user.getUserId(), user.getPhone());
            }
        }
        return result;
    }

    @Transactional(rollbackFor = {Exception.class})
    @Override
    public boolean updateUser(User user) {
        if (StrUtil.isNotEmpty(user.getUsername()) && baseMapper.selectCount(new LambdaQueryWrapper<User>()
                .eq(User::getUsername, user.getUsername())
                .ne(User::getUserId, user.getUserId())) > 0) {
            throw new BusinessException("账号已存在");
        }
        if (StrUtil.isNotEmpty(user.getPhone()) && baseMapper.selectCount(new LambdaQueryWrapper<User>()
                .eq(User::getPhone, user.getPhone())
                .ne(User::getUserId, user.getUserId())) > 0) {
            throw new BusinessException("手机号已存在");
        }
        if (StrUtil.isNotEmpty(user.getEmail()) && baseMapper.selectCount(new LambdaQueryWrapper<User>()
                .eq(User::getEmail, user.getEmail())
                .ne(User::getUserId, user.getUserId())) > 0) {
            throw new BusinessException("邮箱已存在");
        }
        // 更新用户等级
        if (user.getGradeId() != null && !user.getGradeId().equals(0)) {
            userService.updateById(user);
        }
        boolean result = baseMapper.updateById(user) > 0;
        if (result && user.getRoles() != null && user.getRoles().size() > 0) {
            userRoleService.remove(new LambdaUpdateWrapper<UserRole>().eq(UserRole::getUserId, user.getUserId()));
            List<Integer> roleIds = user.getRoles().stream().map(Role::getRoleId).collect(Collectors.toList());
            if (userRoleService.saveBatch(user.getUserId(), roleIds) < roleIds.size()) {
                throw new BusinessException("用户角色添加失败");
            }
        }
        // 用户更新成功后，通过MQ异步同步用户数据到 websopy
        if (result && syncMessageProducer != null) {
            User updatedUser = getAllByUserId(String.valueOf(user.getUserId()));
            if (updatedUser != null) {
                syncMessageProducer.sendUserSyncMessage("websopy", "UPDATE", updatedUser);
                log.info("用户更新后发送MQ消息同步到websopy: userId={}, phone={}", user.getUserId(), user.getPhone());
            }
        }
        return result;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean markAsDeveloper(Integer userId) {
        if (userId == null) {
            return false;
        }
        User user = new User();
        user.setUserId(userId);
        user.setIsDeveloper(true);
        boolean result = updateById(user);
        if (result) {
            // 替换用户角色为 developer：先按用户所在租户找到 developer 角色，删除该用户现有角色后
            // 只绑定 developer，保证用户最终只有「开发者」单一角色（不与原角色并存）
            try {
                User dbUser = getById(userId);
                Integer tenantId = dbUser != null ? dbUser.getTenantId() : null;
                RoleParam roleParam = new RoleParam();
                roleParam.setRoleCode("developer");
                if (tenantId != null) {
                    roleParam.setTenantId(tenantId);
                }
                Role developerRole = roleService.getByRoleCode(roleParam);
                if (developerRole != null && developerRole.getRoleId() != null) {
                    userRoleService.remove(new LambdaUpdateWrapper<UserRole>().eq(UserRole::getUserId, userId));
                    userRoleService.saveBatch(userId, Collections.singletonList(developerRole.getRoleId()));
                    log.info("用户设为开发者并替换角色为 developer: userId={}, roleId={}", userId, developerRole.getRoleId());
                }
            } catch (Exception e) {
                // 角色替换失败不影响 is_developer 标记位落库
                log.warn("替换用户角色为 developer 失败（不影响 is_developer 标记）: userId={}", userId, e);
            }
            // 标记开发者后，通过MQ异步同步用户数据到 websopy
            if (syncMessageProducer != null) {
                User updatedUser = getAllByUserId(String.valueOf(userId));
                if (updatedUser != null) {
                    syncMessageProducer.sendUserSyncMessage("websopy", "UPDATE", updatedUser);
                    log.info("用户设为开发者后同步到websopy: userId={}", userId);
                }
            }
        }
        return result;
    }

    @Override
    public boolean comparePassword(String dbPassword, String inputPassword) {
        return bCryptPasswordEncoder.matches(inputPassword, dbPassword);
    }

    @Override
    public String encodePassword(String password) {
        return password == null ? null : bCryptPasswordEncoder.encode(password);
    }

    @Override
    public User getByPhone(String phone) {
        return getOne(
                new LambdaQueryWrapper<User>()
                        .eq(User::getPhone, phone)
                        .eq(User::getDeleted,0)
                        .orderByDesc(User::getUserId).last("limit 1")
        );
    }

    @Override
    public User getByPhone(String phone,Integer tenantId) {
      return getOne(
        new LambdaQueryWrapper<User>()
          .eq(User::getPhone, phone)
          .eq(User::getTenantId, tenantId)
          .eq(User::getDeleted,0)
          .orderByDesc(User::getUserId).last("limit 1")
      );
    }

    @Override
    public User getByUnionId(UserParam param) {
        return getOne(
                new LambdaQueryWrapper<User>()
                        .eq(User::getUnionid, param.getUnionid())
                        .last("limit 1")
        );
    }

    @Override
    public User getByOauthId(UserParam userParam) {
        return userParam.getOne(baseMapper.getOne(userParam));
    }

    @Override
    public List<User> listStatisticsRel(UserParam param) {
        List<User> list = baseMapper.selectListStatisticsRel(param);
        return list;
    }

    /**
     * 更新用户信息(跨租户)
     *
     * @param user 用户信息
     */
    @Override
    public void updateByUserId(User user) {
        baseMapper.updateByUserId(user);
    }

    @Override
    public User addUser(UserParam userParam) {
        User addUser = new User();
        // 注册用户
        addUser.setStatus(0);
        // 默认审核通过；前端传 auditStatus=0 时走审核流程
        addUser.setAuditStatus(userParam.getAuditStatus() != null ? userParam.getAuditStatus() : 1);
        if(userParam.getUsername() != null){
          addUser.setUsername(userParam.getUsername());
        }
        if(userParam.getEmail() != null){
          addUser.setEmail(userParam.getEmail());
        }
        addUser.setNickname(DesensitizedUtil.mobilePhone(userParam.getPhone()));
        addUser.setPlatform(WEB);
        addUser.setGradeId(2);
        if(userParam.getTemplateId() != null){
          addUser.setTemplateId(userParam.getTemplateId());
        }
        if(userParam.getPhone() != null){
          addUser.setPhone(userParam.getPhone());
        }
        if(userParam.getPassword() != null){
          addUser.setPassword(encodePassword(userParam.getPassword()));
        }else {
          addUser.setPassword(encodePassword(CommonUtil.randomUUID16()));
        }
        if(userParam.getProvince() != null){
          addUser.setProvince(userParam.getProvince());
        }
        if(userParam.getCity() != null){
          addUser.setCity(userParam.getCity());
        }
        if(userParam.getRegion() != null){
          addUser.setRegion(userParam.getRegion());
        }
        if(userParam.getIsAdmin() != null){
          addUser.setIsAdmin(userParam.getIsAdmin());
        }
        if(userParam.getAddress() != null){
          addUser.setAddress(userParam.getAddress());
        }
        if(userParam.getIndustryParent() != null){
          addUser.setIndustryParent(userParam.getIndustryParent());
          addUser.setIndustryChild(userParam.getIndustryChild());
        }
        if (userParam.getGradeId() != null) {
            addUser.setGradeId(userParam.getGradeId());
        }
        addUser.setTenantId(userParam.getTenantId());
        addUser.setRecommend(0);
        // Role assignment:
        // - If roleId is provided (e.g. invite flow), use it (must belong to the same tenant).
        // - Otherwise, fall back to roleCode; default to "user".
        Role role = null;
        if (userParam.getRoleId() != null) {
            role = roleService.getById(userParam.getRoleId());
            if (role != null
                    && addUser.getTenantId() != null
                    && role.getTenantId() != null
                    && !addUser.getTenantId().equals(role.getTenantId())) {
                throw new BusinessException("角色不属于当前租户");
            }
        }
        String roleCode = userParam.getRoleCode();
        if (role == null) {
            roleCode = StrUtil.blankToDefault(roleCode, "user");
            QueryWrapper<Role> roleQw = new QueryWrapper<Role>().eq("role_code", roleCode);
            if (addUser.getTenantId() != null) {
                roleQw.eq("tenant_id", addUser.getTenantId());
            }
            role = roleService.getOne(roleQw, false);
            // If the default "user" role is missing (fresh DB / incomplete init), create it to avoid empty roles.
            if (role == null && addUser.getTenantId() != null && "user".equals(roleCode)) {
                // 校验租户是否存在，否则插入 sys_role 会因外键约束失败（tenant_id 引用 sys_tenant）
                if (tenantService.getById(addUser.getTenantId()) == null) {
                    throw new BusinessException("租户不存在(tenantId=" + addUser.getTenantId() + ")，无法创建默认角色");
                }
                Role defaultRole = new Role();
                defaultRole.setRoleName("注册用户");
                defaultRole.setRoleCode("user");
                defaultRole.setComments("普通注册用户");
                defaultRole.setTenantId(addUser.getTenantId());
                roleService.save(defaultRole);
                role = defaultRole;
            }
        }
        if (role == null) {
            throw new BusinessException("缺少默认角色(role_code=" + (roleCode == null ? "user" : roleCode) + ")，请先初始化角色");
        }
        addUser.setRoleId(role.getRoleId());
        if (saveUser(addUser)) {
            // 添加用户角色
            final UserRole userRole = new UserRole();
            userRole.setUserId(addUser.getUserId());
            userRole.setTenantId(addUser.getTenantId());
            userRole.setRoleId(addUser.getRoleId());
            userRoleService.save(userRole);
        }
        // Ensure caller (e.g. register / invite register) gets non-empty roles/authorities in response.
        addUser.setRoles(userRoleService.listByUserId(addUser.getUserId()));
        addUser.setAuthorities(roleMenuService.listMenuByUserId(addUser.getUserId(), null));
        // addUser内部调用saveUser，saveUser已发送MQ消息，这里不需要重复发送
        return addUser;
    }

    @Override
    public User getAdminByPhone(UserParam param) {
      return baseMapper.selectAdminByPhone(param);
    }

    public User getAdminByPhone(UserParam param,Integer tenantId){
      return baseMapper.selectAdminByPhone(param,tenantId);
    }

    @Override
    public List<User> getAdminsByPhone(LoginParam param){
      final UserParam userParam = new UserParam();
      userParam.setPhone(param.getPhone());
      userParam.setIsAdmin(true);
      if(param.getTemplateId() != null){
        userParam.setTemplateId(param.getTemplateId());
      }
      return baseMapper.selectListAllRel(userParam);
    }

    @Override
    public User getLastLoginSuperAdminByPhone(String phone) {
      return baseMapper.selectLastLoginSuperAdminByPhone(phone);
    }

    @Override
    public User getLastLoginDeveloperByPhone(String phone) {
      return baseMapper.selectLastLoginDeveloperByPhone(phone);
    }

    @Override
    public User getByPhoneAndAdmin(String phone) {
      return baseMapper.selectAdminByPhoneCrossTenant(phone);
    }

    @Override
    public List<User> getSuperAdminsByPhone(String phone) {
      if (StrUtil.isBlank(phone)) {
        return null;
      }
      return baseMapper.selectSuperAdminsByPhone(phone);
    }

    @Override
    public User getSuperAdminByPhoneAndTenantId(String phone, Integer tenantId) {
      if (StrUtil.isBlank(phone) || tenantId == null) {
        return null;
      }
      return baseMapper.selectSuperAdminByPhoneAndTenantId(phone, tenantId);
    }

    @Override
    public List<User> pageAll(UserParam param) {
      return baseMapper.pageRelAll(param);
    }

  @Override
  public User getByUserId(String userId) {
    return baseMapper.getByUserId(userId);
  }

    @Override
    public User getAllByUserId(String userId) {
        return getOne(new LambdaQueryWrapper<User>().eq(User::getUserId, userId).last("limit 1"));
    }

  /**
     * 批量查询用户的角色
     *
     * @param users 用户集合
     */
    private void selectUserRoles(List<User> users) {
        if (users != null && !users.isEmpty()) {
            List<Integer> userIds = users.stream().map(User::getUserId).collect(Collectors.toList());
            List<Role> userRoles = userRoleService.listByUserIds(userIds);
            for (User user : users) {
                List<Role> roles = userRoles.stream().filter(d -> user.getUserId().equals(d.getUserId()))
                        .collect(Collectors.toList());
                user.setRoles(roles);
                // 上级
                UserReferee userReferee = userRefereeService.getByUserId(user.getUserId());
                if (userReferee != null) {
                    User parent = getByIdRel(userReferee.getDealerId());
                    user.setReferee(parent);
                }
            }
        }
    }

    @Override
    public Integer userNumInPark(UserParam param) {
        List<Organization> organizationList = organizationService.list(
                new LambdaQueryWrapper<Organization>()
                        .eq(Organization::getPark, param.getPark())
        );
        if (organizationList != null && !organizationList.isEmpty()) {
            return count(
                    new LambdaQueryWrapper<User>()
                            .in(User::getOrganizationId, organizationList.stream().map(Organization::getOrganizationId).collect(Collectors.toList()))
            );
        }
        return 0;
    }

    @Override
    public Integer orgNumInPark(UserParam param) {
        return organizationService.count(
                new LambdaQueryWrapper<Organization>()
                        .eq(Organization::getPark, param.getPark())
        );
    }

    @Override
    public List<User> findAccountsByPhone(String phone) {
        if (StrUtil.isBlank(phone)) {
            return null;
        }
        return baseMapper.selectAccountsByPhone(phone);
    }

    @Override
    public List<User> findAccountsByEmail(String email) {
        if (StrUtil.isBlank(email)) {
            return null;
        }
        return baseMapper.selectAccountsByEmail(email);
    }

    @Override
    public Integer countAccountsByPhone(String phone) {
        if (StrUtil.isBlank(phone)) {
            return 0;
        }
        return baseMapper.countByPhone(phone);
    }

    @Override
    @Transactional(rollbackFor = Exception.class, isolation = Isolation.SERIALIZABLE)
    public boolean resetUserPassword(String userId, Integer tenantId, String newPassword) {
        if (StrUtil.isBlank(userId) || tenantId == null || StrUtil.isBlank(newPassword)) {
            throw new BusinessException("参数不能为空");
        }

        // 先查询用户是否存在（忽略租户隔离）
        User existingUser = baseMapper.getByUserId(userId);
        if (existingUser == null) {
            throw new BusinessException("用户不存在");
        }

        // 验证租户ID是否匹配
        if (!tenantId.equals(existingUser.getTenantId())) {
            throw new BusinessException("租户信息不匹配");
        }

        // 加密新密码
        String encodedPassword = encodePassword(newPassword);

        // 使用跨租户更新方法
        User updateUser = new User();
        updateUser.setUserId(Integer.parseInt(userId));
        updateUser.setPassword(encodedPassword);
        baseMapper.updateByUserId(updateUser);

        return true;
    }
}
