package cn.iocoder.byzs.module.system.service.invitecode;

import cn.hutool.core.collection.CollUtil;
import cn.iocoder.byzs.framework.common.pojo.PageParam;
import cn.iocoder.byzs.framework.common.pojo.PageResult;
import cn.iocoder.byzs.framework.common.util.object.BeanUtils;
import cn.iocoder.byzs.framework.common.util.string.StrUtils;
import cn.iocoder.byzs.framework.tenant.core.util.TenantUtils;
import cn.iocoder.byzs.module.system.controller.admin.invitecode.vo.InviteCodePageReqVO;
import cn.iocoder.byzs.module.system.controller.admin.invitecode.vo.InviteCodeRespVO;
import cn.iocoder.byzs.module.system.controller.admin.invitecode.vo.InviteCodeSaveReqVO;
import cn.iocoder.byzs.module.system.dal.dataobject.invitecode.InviteCodeDO;
import cn.iocoder.byzs.module.system.dal.dataobject.permission.RoleDO;
import cn.iocoder.byzs.module.system.dal.dataobject.tenant.TenantDO;
import cn.iocoder.byzs.module.system.dal.dataobject.user.AdminUserDO;
import cn.iocoder.byzs.module.system.dal.mysql.invitecode.InviteCodeMapper;
import cn.iocoder.byzs.module.system.dal.mysql.permission.RoleMapper;
import cn.iocoder.byzs.module.system.dal.mysql.tenant.TenantMapper;
import cn.iocoder.byzs.module.system.dal.mysql.user.AdminUserMapper;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import jakarta.annotation.Resource;
import org.springframework.stereotype.Service;
import org.springframework.validation.annotation.Validated;

import java.util.*;
import java.util.stream.Collectors;

import static cn.iocoder.byzs.framework.common.exception.util.ServiceExceptionUtil.exception;
import static cn.iocoder.byzs.module.system.enums.ErrorCodeConstants.INVITE_CODE_NOT_EXISTS;

/**
 * 邀请码 Service 实现类
 *
 * @author lyb
 */
@Service
@Validated
public class InviteCodeServiceImpl implements InviteCodeService {

    @Resource
    private InviteCodeMapper inviteCodeMapper;

    @Resource
    private RoleMapper roleMapper;

    @Resource
    private TenantMapper tenantMapper;

    @Resource
    private AdminUserMapper userMapper;

    @Override
    public Long createInviteCode(InviteCodeSaveReqVO createReqVO) {
        // 批量生成邀请码
        if ("batch".equals(createReqVO.getType())) {
            Integer batchCount = createReqVO.getBatchCount();

            // 生成批量邀请码
            List<InviteCodeDO> inviteCodeList = new ArrayList<>(batchCount);
            for (int i = 0; i < batchCount; i++) {
                InviteCodeDO inviteCode = BeanUtils.toBean(createReqVO, InviteCodeDO.class);
                // 生成随机邀请码
                String randomCode = generateRandomCode(10);
                // 如果有前缀，则拼接前缀
                if (createReqVO.getCode() != null && !createReqVO.getCode().isEmpty()) {
                    inviteCode.setCode(createReqVO.getCode() + randomCode);
                } else {
                    inviteCode.setCode(randomCode);
                }
                inviteCodeList.add(inviteCode);
            }

            // 批量插入
            inviteCodeMapper.insertBatch(inviteCodeList);

            // 返回第一个生成的邀请码ID
            return inviteCodeList.get(0).getId();
        }
        // 单条插入
        else {
            InviteCodeDO inviteCode = BeanUtils.toBean(createReqVO, InviteCodeDO.class);
            // 如果没有提供邀请码，则生成一个
            if (inviteCode.getCode() == null || inviteCode.getCode().isEmpty()) {
                inviteCode.setCode(generateRandomCode(10));
            }
            inviteCodeMapper.insert(inviteCode);
            return inviteCode.getId();
        }
    }

    /**
     * 生成指定长度的随机邀请码
     * @param length 邀请码长度
     * @return 随机邀请码
     */
    private String generateRandomCode(int length) {
        // 定义字符集：大小写字母 + 数字
        String chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
        StringBuilder sb = new StringBuilder(length);
        Random random = new Random();

        for (int i = 0; i < length; i++) {
            int index = random.nextInt(chars.length());
            sb.append(chars.charAt(index));
        }

        return sb.toString();
    }

    @Override
    public void updateInviteCode(InviteCodeSaveReqVO updateReqVO) {
        // 校验存在
        validateInviteCodeExists(updateReqVO.getId());
        // 更新
        InviteCodeDO updateObj = BeanUtils.toBean(updateReqVO, InviteCodeDO.class);
        inviteCodeMapper.updateById(updateObj);
    }

    @Override
    public void deleteInviteCode(Long id) {
        // 校验存在
        validateInviteCodeExists(id);
        // 删除
        inviteCodeMapper.deleteById(id);
    }

    @Override
        public void deleteInviteCodeListByIds(List<Long> ids) {
        // 校验存在
        validateInviteCodeExists(ids);
        // 删除
        inviteCodeMapper.deleteByIds(ids);
        }

    private void validateInviteCodeExists(List<Long> ids) {
        List<InviteCodeDO> list = inviteCodeMapper.selectByIds(ids);
        if (CollUtil.isEmpty(list) || list.size() != ids.size()) {
            throw exception(INVITE_CODE_NOT_EXISTS);
        }
    }

    private void validateInviteCodeExists(Long id) {
        if (inviteCodeMapper.selectById(id) == null) {
            throw exception(INVITE_CODE_NOT_EXISTS);
        }
    }

    @Override
    public InviteCodeDO getInviteCode(Long id) {
        return inviteCodeMapper.selectById(id);
    }

    @Override
    public InviteCodeDO getUnusedInviteCode(String inviteCode) {
        return inviteCodeMapper.selectOne(new LambdaQueryWrapper<InviteCodeDO>()
                .eq(InviteCodeDO::getCode, inviteCode));
    }

    @Override
    public List<InviteCodeDO> getInviteCodeByUserId(Long useUserId) {
        return inviteCodeMapper.selectList(new LambdaQueryWrapper<InviteCodeDO>()
                .eq(InviteCodeDO::getUseUserId, useUserId));
    }

    @Override
    public PageResult<InviteCodeRespVO> getInviteCodePage(InviteCodePageReqVO pageReqVO) {
        // 1. 首先查询所有符合条件的数据（不分页），因为需要进行内存筛选
        // 临时保存分页参数，查询完后恢复
        Integer originalPageSize = pageReqVO.getPageSize();
        Integer originalPageNo = pageReqVO.getPageNo();
        
        // 设置不分页，查询所有数据
        pageReqVO.setPageSize(PageParam.PAGE_SIZE_NONE);
        PageResult<InviteCodeDO> inviteCodeDOPageResult = inviteCodeMapper.selectPage(pageReqVO);
        List<InviteCodeDO> list = inviteCodeDOPageResult.getList();
        
        // 恢复分页参数
        pageReqVO.setPageSize(originalPageSize);
        pageReqVO.setPageNo(originalPageNo);

        // 2. 转换为RespVO并填充关联数据
        // 取所有角色ID
        Set<Long> roleIdSet = list.stream().map(InviteCodeDO::getRoleIds).filter(Objects::nonNull).flatMap(roleIds -> StrUtils.splitToLongSet(roleIds).stream()).collect(Collectors.toSet());
        List<RoleDO> roleList = roleIdSet.isEmpty() ? Collections.emptyList() : TenantUtils.executeIgnore(() ->
                roleMapper.selectBatchIds(roleIdSet)
        );
        Map<Long, String> roleMap = roleList.stream().collect(Collectors.toMap(RoleDO::getId, RoleDO::getName));

        // 取所有用户ID
        Set<Long> userIdSet = list.stream().map(InviteCodeDO::getUseUserId).filter(Objects::nonNull).collect(Collectors.toSet());
        List<AdminUserDO> userList = userIdSet.isEmpty() ? Collections.emptyList() : TenantUtils.executeIgnore(() ->
                userMapper.selectBatchIds(userIdSet)
        );
        Map<Long, String> userMap = userList.stream().collect(Collectors.toMap(AdminUserDO::getId, AdminUserDO::getNickname));

        // 取所有租户ID
        Set<Long> userTenantIdSet = list.stream().map(InviteCodeDO::getUseUserTenantId).filter(Objects::nonNull).collect(Collectors.toSet());
        List<TenantDO> tenantList = userTenantIdSet.isEmpty() ? Collections.emptyList() : TenantUtils.executeIgnore(() ->
                tenantMapper.selectBatchIds(userTenantIdSet)
        );
        Map<Long, String> tenantMap = tenantList.stream().collect(Collectors.toMap(TenantDO::getId, TenantDO::getName));

        // 转换为RespVO
        List<InviteCodeRespVO> respVOList = list.stream().map(inviteCode -> {
            InviteCodeRespVO respVO = BeanUtils.toBean(inviteCode, InviteCodeRespVO.class);

            // 填充角色名称
            if (inviteCode.getRoleIds() != null) {
                Set<String> roleNames = StrUtils.splitToLongSet(inviteCode.getRoleIds()).stream()
                        .map(roleMap::get)
                        .filter(Objects::nonNull)
                        .collect(Collectors.toSet());
                respVO.setRoleNames(roleNames);
                respVO.setRoleIds(inviteCode.getRoleIds());
            }

            // 填充用户名
            if (inviteCode.getUseUserId() != null) {
                respVO.setUseUserName(userMap.get(inviteCode.getUseUserId()));
            }

            // 填充租户名称
            if (inviteCode.getUseUserTenantId() != null) {
                respVO.setUseUserTenantName(tenantMap.get(inviteCode.getUseUserTenantId()));
            }

            return respVO;
        }).collect(Collectors.toList());

        // 3. 进行内存筛选
        List<InviteCodeRespVO> filteredRespVOList = respVOList;

        // 按角色名称筛选
        if (pageReqVO.getRoleName() != null && !pageReqVO.getRoleName().isEmpty()) {
            Set<String> roleNameFilters = Arrays.stream(pageReqVO.getRoleName().split(",")).map(String::trim).collect(Collectors.toSet());
            filteredRespVOList = filteredRespVOList.stream()
                    .filter(respVO -> {
                        if (respVO.getRoleNames() == null || respVO.getRoleNames().isEmpty()) {
                            return false;
                        }
                        // 只要角色名称集合中有一个匹配筛选条件，就保留该记录
                        return roleNameFilters.stream()
                                .anyMatch(filter -> respVO.getRoleNames().stream()
                                        .anyMatch(roleName -> roleName.contains(filter)));
                    })
                    .collect(Collectors.toList());
        }

        // 按用户名筛选
        if (pageReqVO.getUseUserName() != null && !pageReqVO.getUseUserName().isEmpty()) {
            filteredRespVOList = filteredRespVOList.stream()
                    .filter(respVO -> {
                        if (respVO.getUseUserName() == null) {
                            return false;
                        }
                        return respVO.getUseUserName().contains(pageReqVO.getUseUserName());
                    })
                    .collect(Collectors.toList());
        }

        // 按租户名称筛选
        if (pageReqVO.getUseUserTenantName() != null && !pageReqVO.getUseUserTenantName().isEmpty()) {
            filteredRespVOList = filteredRespVOList.stream()
                    .filter(respVO -> {
                        if (respVO.getUseUserTenantName() == null) {
                            return false;
                        }
                        return respVO.getUseUserTenantName().contains(pageReqVO.getUseUserTenantName());
                    })
                    .collect(Collectors.toList());
        }

        // 4. 对筛选后的结果进行分页
        int pageNo = pageReqVO.getPageNo();
        int pageSize = pageReqVO.getPageSize();
        int total = filteredRespVOList.size();
        
        // 计算分页起始位置
        int start = (pageNo - 1) * pageSize;
        int end = Math.min(start + pageSize, total);
        
        // 截取当前页数据
        List<InviteCodeRespVO> pagedList = (start < end) ? filteredRespVOList.subList(start, end) : Collections.emptyList();

        // 5. 返回正确的分页结果
        return new PageResult<>(pagedList, (long) total);
    }

}