package com.hotwj.platform.resourceManagement.personnelConfig.service.impl;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.crypto.digest.BCrypt;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.hotwj.platform.common.utils.PasswordUtils;
import com.hotwj.platform.resourceManagement.company.domain.SysUserLoginPort;
import com.hotwj.platform.resourceManagement.company.mapper.SysUserLoginPortMapper;
import com.hotwj.platform.resourceManagement.company.service.ISysUserLoginPortService;
import com.hotwj.platform.resourceManagement.govEnterpriseUnit.domain.HotGovEnterpriseUnit;
import com.hotwj.platform.resourceManagement.govEnterpriseUnit.mapper.HotGovEnterpriseUnitMapper;
import com.hotwj.platform.resourceManagement.personnelConfig.domain.HotPersonnelConfig;
import com.hotwj.platform.resourceManagement.personnelConfig.domain.bo.HotPersonnelConfigBo;
import com.hotwj.platform.resourceManagement.personnelConfig.domain.vo.HotPersonnelConfigVo;
import com.hotwj.platform.resourceManagement.personnelConfig.mapper.HotPersonnelConfigMapper;
import com.hotwj.platform.resourceManagement.personnelConfig.service.IHotPersonnelConfigService;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.dromara.common.core.exception.ServiceException;
import org.dromara.common.core.utils.MapstructUtils;
import org.dromara.common.core.utils.StringUtils;
import org.dromara.common.mybatis.core.page.PageQuery;
import org.dromara.common.mybatis.core.page.TableDataInfo;
import org.dromara.system.domain.SysUser;
import org.dromara.system.domain.SysUserRole;
import org.dromara.system.mapper.SysUserMapper;
import org.dromara.system.mapper.SysUserRoleMapper;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.Collection;
import java.util.List;
import java.util.Map;

import static com.hotwj.platform.resourceManagement.company.service.ISysUserLoginPortService.AGENT_ROLE_ID;
import static com.hotwj.platform.resourceManagement.company.service.ISysUserLoginPortService.GOVERNMENT_ROLE_ID;

/**
 * 人员配置Service业务层处理
 *
 * @author shihongwei
 * @date 2026-01-12
 */
@Slf4j
@RequiredArgsConstructor
@Service
public class HotPersonnelConfigServiceImpl implements IHotPersonnelConfigService {

    private final HotPersonnelConfigMapper baseMapper;
    private final SysUserMapper sysUserMapper;
    private final SysUserRoleMapper sysUserRoleMapper;
    private final SysUserLoginPortMapper sysUserLoginPortMapper;
    private final HotGovEnterpriseUnitMapper enterpriseUnitMapper;

    /**
     * 查询人员配置
     *
     * @param id 主键
     * @return 人员配置
     */
    @Override
    public HotPersonnelConfigVo queryById(Long id) {
        HotPersonnelConfigVo vo = baseMapper.selectVoById(id);
        if (vo != null) {
            vo.setLoginPassword(null);
        }
        return vo;
    }

    /**
     * 分页查询人员配置列表
     *
     * @param bo        查询条件
     * @param pageQuery 分页参数
     * @return 人员配置分页列表
     */
    @Override
    public TableDataInfo<HotPersonnelConfigVo> queryPageList(HotPersonnelConfigBo bo, PageQuery pageQuery) {
        LambdaQueryWrapper<HotPersonnelConfig> lqw = buildQueryWrapper(bo);
        Page<HotPersonnelConfigVo> result = baseMapper.selectVoPage(pageQuery.build(), lqw);
        return TableDataInfo.build(result);
    }

    /**
     * 查询符合条件的人员配置列表
     *
     * @param bo 查询条件
     * @return 人员配置列表
     */
    @Override
    public List<HotPersonnelConfigVo> queryList(HotPersonnelConfigBo bo) {
        LambdaQueryWrapper<HotPersonnelConfig> lqw = buildQueryWrapper(bo);
        return baseMapper.selectVoList(lqw);
    }

    private LambdaQueryWrapper<HotPersonnelConfig> buildQueryWrapper(HotPersonnelConfigBo bo) {
        Map<String, Object> params = bo.getParams();
        LambdaQueryWrapper<HotPersonnelConfig> lqw = Wrappers.lambdaQuery();
        lqw.orderByAsc(HotPersonnelConfig::getId);
        lqw.eq(bo.getUnitId() != null, HotPersonnelConfig::getUnitId, bo.getUnitId());
        lqw.like(StringUtils.isNotBlank(bo.getStaffName()), HotPersonnelConfig::getStaffName, bo.getStaffName());
        lqw.like(StringUtils.isNotBlank(bo.getMobile()), HotPersonnelConfig::getMobile, bo.getMobile());
        lqw.like(StringUtils.isNotBlank(bo.getPositionName()), HotPersonnelConfig::getPositionName, bo.getPositionName());
        lqw.eq(bo.getPermissionType() != null, HotPersonnelConfig::getPermissionType, bo.getPermissionType());
        lqw.eq(StringUtils.isNotBlank(bo.getLoginAccount()), HotPersonnelConfig::getLoginAccount, bo.getLoginAccount());
        lqw.eq(StringUtils.isNotBlank(bo.getLoginPassword()), HotPersonnelConfig::getLoginPassword, bo.getLoginPassword());
        lqw.eq(bo.getIsEnabled() != null, HotPersonnelConfig::getIsEnabled, bo.getIsEnabled());
        lqw.eq(bo.getCreateBy() != null, HotPersonnelConfig::getCreateBy, bo.getCreateBy());
        lqw.eq(bo.getCreateTime() != null, HotPersonnelConfig::getCreateTime, bo.getCreateTime());
        lqw.eq(bo.getIsDeleted() != null, HotPersonnelConfig::getIsDeleted, bo.getIsDeleted());
        return lqw;
    }

    /**
     * 新增人员配置
     *
     * @param bo 人员配置
     * @return 是否新增成功
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public Boolean insertByBo(HotPersonnelConfigBo bo) {
        HotPersonnelConfig add = MapstructUtils.convert(bo, HotPersonnelConfig.class);
        validEntityBeforeSave(add);
        boolean flag = baseMapper.insert(add) > 0;
        if (flag) {
            bo.setId(add.getId());
            syncUser(bo);
        }
        return flag;
    }

    /**
     * 修改人员配置
     *
     * @param bo 人员配置
     * @return 是否修改成功
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public Boolean updateByBo(HotPersonnelConfigBo bo) {
        HotPersonnelConfig update = MapstructUtils.convert(bo, HotPersonnelConfig.class);
        validEntityBeforeSave(update);
        boolean flag = baseMapper.updateById(update) > 0;
        if (flag) {
            syncUser(bo);
        }
        return flag;
    }

    /**
     * 同步用户信息
     */
    private void syncUser(HotPersonnelConfigBo bo) {
        Long unitId = bo.getUnitId();
        String staffName = bo.getStaffName();
        String mobile = bo.getMobile();
        String loginPassword = bo.getLoginPassword();
        Long isEnabled = bo.getIsEnabled();
        Long isDeleted = bo.getIsDeleted();

        HotGovEnterpriseUnit enterpriseUnit = enterpriseUnitMapper.selectById(unitId);

        if (enterpriseUnit == null) {
            throw new IllegalArgumentException("当前单位不存在");
        }

        String loginPort = ISysUserLoginPortService.GOVERNMENT_PORT;
        Long roleId = GOVERNMENT_ROLE_ID;
        if (enterpriseUnit.getUnitType() == 2) {
            loginPort = ISysUserLoginPortService.AGENT_PORT;
            roleId = AGENT_ROLE_ID;
        }

        // 1. 查询用户是否存在
        SysUser sysUser = sysUserMapper.selectOne(new LambdaQueryWrapper<SysUser>().eq(SysUser::getPhonenumber, mobile));
        if (sysUser == null) {
            // 不存在则创建
            if (isDeleted != null && isDeleted == 1) {
                // 如果是删除状态，且用户不存在，则无需创建
                return;
            }
            sysUser = new SysUser();
            sysUser.setPhonenumber(bo.getMobile());
            sysUser.setPassword(BCrypt.hashpw(loginPassword));
            sysUser.setUserType("sys_user");
            sysUserMapper.insert(sysUser);
        } else {
            // 存在则更新
            // 校验：手机号在当前端口不能重复
            assertPhoneNotDuplicateInPort(mobile, loginPort, unitId, sysUser.getUserId());
            sysUser.setPhonenumber(bo.getMobile());
            if (StringUtils.isNotBlank(loginPassword)) {
                sysUser.setPassword(BCrypt.hashpw(loginPassword));
            }
            sysUserMapper.updateById(sysUser);
        }

        Long userId = sysUser.getUserId();

        // 2. 绑定政府/代理端登录端口（通过端口状态控制启用/禁用）
        List<SysUserLoginPort> portList = sysUserLoginPortMapper.selectList(new LambdaQueryWrapper<SysUserLoginPort>()
                .eq(SysUserLoginPort::getUserId, userId)
                .eq(SysUserLoginPort::getCompanyId, unitId)
                .eq(SysUserLoginPort::getLoginPort, loginPort));

        if (isDeleted != null && isDeleted == 1) {
            // 删除：禁用当前端口
            for (SysUserLoginPort port : portList) {
                port.setStatus(0);
                sysUserLoginPortMapper.updateById(port);
            }
            return;
        }

        boolean enablePort = isEnabled == null || isEnabled == 1;

        if (CollUtil.isEmpty(portList)) {
            // 没有端口记录则创建一条
            SysUserLoginPort port = new SysUserLoginPort();
            port.setUserId(userId);
            port.setUsername(staffName);
            port.setCompanyId(unitId);
            port.setLoginPort(loginPort);
            port.setIsDefault(0);
            port.setStatus(enablePort ? 1 : 0);
            port.setSubPassword(PasswordUtils.createPassword(loginPassword));
            sysUserLoginPortMapper.insert(port);
        } else {
            // 修改当前端口的用户名及启用状态
            for (SysUserLoginPort port : portList) {
                port.setUsername(staffName);
                port.setStatus(enablePort ? 1 : 0);
                port.setSubPassword(PasswordUtils.createPassword(loginPassword));
                sysUserLoginPortMapper.updateById(port);
            }
        }

        // 3. 绑定业务角色 (GOVERNMENT_ROLE_ID / AGENT_ROLE_ID)

        // 先清除该用户在该单位下的其他角色（根据业务需求，这里参考安全管理员逻辑：先解除其他角色，再关联当前角色）
        sysUserRoleMapper.delete(new LambdaQueryWrapper<SysUserRole>()
                .eq(SysUserRole::getUserId, userId)
                .eq(SysUserRole::getRoleId, roleId)
                .eq(SysUserRole::getCompanyId, unitId)
                .eq(SysUserRole::getLoginPort, loginPort));

        if (enablePort) {
            SysUserRole userRole = new SysUserRole();
            userRole.setUserId(userId);
            userRole.setRoleId(roleId);
            userRole.setCompanyId(unitId);
            userRole.setLoginPort(loginPort);
            sysUserRoleMapper.insert(userRole);
        }
    }

    /**
     * 保存前的数据校验
     */
    private void validEntityBeforeSave(HotPersonnelConfig entity) {
        if (StringUtils.isNotBlank(entity.getMobile())) {
            // 1. 推断当前单位对应的单位类型（即登录端口）
            HotGovEnterpriseUnit unit = enterpriseUnitMapper.selectById(entity.getUnitId());
            if (unit == null) {
                throw new ServiceException("所属单位不存在");
            }
            Long unitType = unit.getUnitType(); // 1=政企(政府端), 2=代理商(代理商端)

            // 2. 通过 SQL 联查判断该端口下手机号是否重复
            Long count = baseMapper.checkPhoneExist(entity.getMobile(), unitType, entity.getId());

            if (count != null && count > 0) {
                String portName = (unitType == 2) ? "代理商端" : "政府监管端";
                throw new ServiceException("该手机号已在" + portName + "注册（可能在其他单位），请勿重复添加");
            }
        }
    }

    /**
     * 校验并批量删除人员配置信息
     *
     * @param ids     待删除的主键集合
     * @param isValid 是否进行有效性校验
     * @return 是否删除成功
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public Boolean deleteWithValidByIds(Collection<Long> ids, Boolean isValid) {
        if (isValid) {
            //TODO 做一些业务上的校验,判断是否需要校验
        }
        // 1. 获取要删除的人员配置信息
        List<HotPersonnelConfig> list = baseMapper.selectBatchIds(ids);
        if (CollUtil.isNotEmpty(list)) {
            for (HotPersonnelConfig config : list) {
                removeUserByConfig(config);
            }
        }
        return baseMapper.deleteByIds(ids) > 0;
    }

    /**
     * 校验手机号在当前端口是否重复（排除当前用户）
     */
    private void assertPhoneNotDuplicateInPort(String mobile, String loginPort, Long unitId, Long excludeUserId) {
        if (StringUtils.isBlank(mobile) || unitId == null || StringUtils.isBlank(loginPort)) {
            return;
        }
        List<SysUser> users = sysUserMapper.selectList(new LambdaQueryWrapper<SysUser>()
                .eq(SysUser::getPhonenumber, mobile));
        if (CollUtil.isEmpty(users)) {
            return;
        }
        for (SysUser u : users) {
            if (u.getUserId() != null && !u.getUserId().equals(excludeUserId)) {
                Long count = sysUserLoginPortMapper.selectCount(new LambdaQueryWrapper<SysUserLoginPort>()
                        .eq(SysUserLoginPort::getUserId, u.getUserId())
                        .eq(SysUserLoginPort::getCompanyId, unitId)
                        .eq(SysUserLoginPort::getLoginPort, loginPort)
                        .eq(SysUserLoginPort::getStatus, 1));
                if (count != null && count > 0) {
                    throw new org.dromara.common.core.exception.ServiceException("该手机号已在当前端口被使用");
                }
            }
        }
    }

    private void removeUserByConfig(HotPersonnelConfig config) {
        String loginAccount = config.getLoginAccount();
        Long unitId = config.getUnitId();
        if (StringUtils.isBlank(loginAccount) || unitId == null) {
            return;
        }

        // 1. 查询对应的 SysUser
        SysUser sysUser = sysUserMapper.selectOne(new LambdaQueryWrapper<SysUser>().eq(SysUser::getUserName, loginAccount));
        if (sysUser == null) {
            return;
        }
        Long userId = sysUser.getUserId();

        // 2. 删除该单位下的角色绑定 (SysUserRole)
        sysUserRoleMapper.delete(new LambdaQueryWrapper<SysUserRole>()
                .eq(SysUserRole::getUserId, userId)
                .eq(SysUserRole::getCompanyId, unitId));

        // 3. 删除该单位下的端口绑定 (SysUserCompanyRole)
        sysUserLoginPortMapper.delete(new LambdaQueryWrapper<SysUserLoginPort>()
                .eq(SysUserLoginPort::getUserId, userId)
                .eq(SysUserLoginPort::getCompanyId, unitId));

        // 4. 检查该用户是否还有其他绑定，如果没有则删除用户
        // 检查是否还有其他端口
        Long portCount = sysUserLoginPortMapper.selectCount(new LambdaQueryWrapper<SysUserLoginPort>()
                .eq(SysUserLoginPort::getUserId, userId));

        // 检查是否还有其他角色 (通常端口和角色是成对的，但为了保险起见检查两者，或者只检查端口即可)
        // 这里只检查端口即可，因为没有端口就无法登录
        if (portCount == 0) {
            sysUserMapper.deleteById(userId);
            log.info("用户 {} 已无关联企业端口，执行删除", loginAccount);
        }
    }
}
