package com.yingpaipay.business.service.impl;

import com.baomidou.mybatisplus.core.metadata.IPage;
import com.yingpaipay.business.domain.Folder;
import com.yingpaipay.business.domain.bo.*;
import com.yingpaipay.business.domain.vo.*;
import com.yingpaipay.business.enumeration.ProjectStatusEnum;
import com.yingpaipay.business.mapper.FolderMapper;
import com.yingpaipay.system.domain.SysUserFolder;
import com.yingpaipay.system.domain.SysUserProjects;
import com.yingpaipay.system.mapper.SysUserFolderMapper;
import com.yingpaipay.system.mapper.SysUserProjectsMapper;
import org.dromara.common.core.utils.MapstructUtils;
import org.dromara.common.core.utils.StringUtils;
import org.dromara.common.mybatis.core.page.TableDataInfo;
import org.dromara.common.mybatis.core.page.PageQuery;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.dromara.common.mybatis.helper.DataBaseHelper;
import org.dromara.common.satoken.utils.LoginHelper;
import org.dromara.system.domain.SysUser;
import org.dromara.system.mapper.SysUserMapper;
import org.dromara.system.service.ISysDeptService;
import org.dromara.system.service.ISysDictTypeService;
import org.dromara.system.service.ISysOssService;
import org.springframework.stereotype.Service;
import com.yingpaipay.business.domain.Project;
import com.yingpaipay.business.mapper.ProjectMapper;
import com.yingpaipay.business.service.IProjectService;

import java.util.*;

/**
 * 项目管理Service业务层处理
 *
 * @author Huanyi
 * @date 2025-12-05
 */
@Slf4j
@RequiredArgsConstructor
@Service
public class ProjectServiceImpl implements IProjectService {

    private final ProjectMapper baseMapper;
    private final SysUserProjectsMapper userProjectsMapper;
    private final SysUserMapper userMapper;
    private final SysUserFolderMapper userFolderMapper;

    private final ISysOssService ossService;
    private final ISysDeptService deptService;

    /**
     * 查询项目管理
     *
     * @param id 主键
     * @return 项目管理
     */
    @Override
    public ProjectVo queryById(Long id) {
        ProjectVo vo = baseMapper.selectVoById(id);
        if (vo.getIcon() != null) {
            vo.setIconUrl(ossService.getById(vo.getIcon()).getUrl());
        }
        return vo;
    }

    /**
     * 分页查询项目管理列表
     *
     * @param bo        查询条件
     * @param pageQuery 分页参数
     * @return 项目管理分页列表
     */
    @Override
    public TableDataInfo<ProjectVo> queryPageList(ProjectBo bo, PageQuery pageQuery) {
        LambdaQueryWrapper<Project> lqw = buildQueryWrapper(bo);
        Page<ProjectVo> result = baseMapper.selectVoPage(pageQuery.build(), lqw);
        List<Long> iconIds = new ArrayList<>();
        result.getRecords().forEach(e -> iconIds.add(e.getIcon()));
        if (!iconIds.isEmpty()) {
            Map<Long, String> iconMap = new HashMap<>();
            ossService.listByIds(iconIds).forEach(e -> iconMap.put(e.getOssId(), e.getUrl()));
            result.getRecords().forEach(e -> e.setIconUrl(iconMap.get(e.getIcon())));
        }
        return TableDataInfo.build(result);
    }

    /**
     * 查询符合条件的项目管理列表
     *
     * @param bo 查询条件
     * @return 项目管理列表
     */
    @Override
    public List<ProjectVo> queryList(ProjectBo bo) {
        LambdaQueryWrapper<Project> lqw = buildQueryWrapper(bo);
        return baseMapper.selectVoList(lqw);
    }

    private LambdaQueryWrapper<Project> buildQueryWrapper(ProjectBo bo) {
        Map<String, Object> params = bo.getParams();
        LambdaQueryWrapper<Project> lqw = Wrappers.lambdaQuery();
        lqw.orderByDesc(Project::getId);
        lqw.like(StringUtils.isNotBlank(bo.getCode()), Project::getCode, bo.getCode());
        lqw.like(StringUtils.isNotBlank(bo.getName()), Project::getName, bo.getName());
        lqw.eq(StringUtils.isNotBlank(bo.getLanguage()), Project::getLanguage, bo.getLanguage());
        lqw.eq(StringUtils.isNotBlank(bo.getType()), Project::getType, bo.getType());
        lqw.eq(bo.getStatus() != null, Project::getStatus, bo.getStatus());
        lqw.like(StringUtils.isNotBlank(bo.getPdGpd()), Project::getPdGpd, bo.getPdGpd());
        lqw.like(StringUtils.isNotBlank(bo.getPmGpm()), Project::getPmGpm, bo.getPmGpm());
        lqw.like(StringUtils.isNotBlank(bo.getCtaGcta()), Project::getCtaGcta, bo.getCtaGcta());
        lqw.like(StringUtils.isNotBlank(bo.getSponsor()), Project::getSponsor, bo.getSponsor());
        lqw.like(StringUtils.isNotBlank(bo.getCro()), Project::getCro, bo.getCro());
        lqw.between(params.get("beginStartTime") != null && params.get("endStartTime") != null,
            Project::getStartTime, params.get("beginStartTime"), params.get("endStartTime"));
        lqw.between(params.get("beginEndTime") != null && params.get("endEndTime") != null,
            Project::getEndTime, params.get("beginEndTime"), params.get("endEndTime"));
        lqw.between(params.get("beginCreateTime") != null && params.get("endCreateTime") != null,
            Project::getCreateTime, params.get("beginCreateTime"), params.get("endCreateTime"));
        lqw.between(params.get("beginUpdateTime") != null && params.get("endUpdateTime") != null,
            Project::getUpdateTime, params.get("beginUpdateTime"), params.get("endUpdateTime"));

        // TODO 只有拥有该项目数据权限的人才能够在列表中看到该项目
        String projects = userProjectsMapper.selectOne(
            Wrappers.lambdaQuery(SysUserProjects.class)
                .eq(SysUserProjects::getUserId, LoginHelper.getUserId())
        ).getProjects();
        if (projects.isEmpty()) {
            lqw.in(Project::getId, List.of(-1L));
        } else if (!projects.equals("*")) {
            lqw.in(Project::getId, Arrays.stream(projects.split(",")).map(Long::valueOf).toList());
        }

        return lqw;
    }

    /**
     * 新增项目管理
     *
     * @param bo 项目管理
     * @return 是否新增成功
     */
    @Override
    public Boolean insertByBo(ProjectBo bo) {
        Project add = MapstructUtils.convert(bo, Project.class);
        validEntityBeforeSave(add);
        boolean flag = baseMapper.insert(add) > 0;
        if (flag) {
            bo.setId(add.getId());
        }
        return flag;
    }

    /**
     * 修改项目管理
     *
     * @param bo 项目管理
     * @return 是否修改成功
     */
    @Override
    public Boolean updateByBo(ProjectBo bo) {
        Project update = MapstructUtils.convert(bo, Project.class);
        validEntityBeforeSave(update);
        return baseMapper.updateById(update) > 0;
    }

    /**
     * 保存前的数据校验
     */
    private void validEntityBeforeSave(Project entity) {
        //TODO 做一些数据校验,如唯一约束
    }

    /**
     * 校验并批量删除项目管理信息
     *
     * @param ids     待删除的主键集合
     * @param isValid 是否进行有效性校验
     * @return 是否删除成功
     */
    @Override
    public Boolean deleteWithValidByIds(Collection<Long> ids, Boolean isValid) {
        if (isValid) {
            //TODO 做一些业务上的校验,判断是否需要校验
        }
        return baseMapper.deleteByIds(ids) > 0;
    }

    @Override
    public List<ProjectListByNameVo> getListByName(String name) {
        List<ProjectListByNameVo> vos = new ArrayList<>();
        baseMapper.selectList(
            Wrappers.lambdaQuery(Project.class)
                .like(StringUtils.isNotBlank(name), Project::getName, name)
        ).forEach(e -> {
            ProjectListByNameVo vo = new ProjectListByNameVo();
            vo.setId(e.getId());
            vo.setName(e.getName());
            vos.add(vo);
        });
        return vos;
    }

    @Override
    public List<ProjectListByNameVo> getList() {
        List<ProjectListByNameVo> vos = new ArrayList<>();
        baseMapper.selectList().forEach(e -> {
            ProjectListByNameVo vo = new ProjectListByNameVo();
            vo.setId(e.getId());
            vo.setName(e.getName());
            vos.add(vo);
        });
        return vos;
    }

    @Override
    public int updateStatus(ProjectUpdateStatusBo bo) {
        return baseMapper.update(
            Wrappers.lambdaUpdate(Project.class)
                .eq(Project::getId, bo.getId())
                .set(Project::getStatus, bo.getStatus())
        );
    }

    @Override
    public TableDataInfo<ProjectMemberListVo> selectMemberListById(Long id, PageQuery pageQuery) {
        List<Long> userIds = new ArrayList<>();
        Page<SysUserProjects> page = userProjectsMapper.selectPage(
            pageQuery.build(),
            Wrappers.lambdaQuery(SysUserProjects.class)
                .and(wrapper -> wrapper
                    .eq(SysUserProjects::getProjects, "*")
                    .or()
                    .apply(DataBaseHelper.findInSet(id, "projects")))
                .orderByDesc(SysUserProjects::getUserId)
        );
        page.getRecords().forEach(e -> userIds.add(e.getUserId()));
        if (userIds.isEmpty()) {
            return TableDataInfo.build();
        }
        Map<Long, SysUser> userMap = new HashMap<>();
        List<Long> deptIds = new ArrayList<>();
        Map<Long, String> deptMap = new HashMap<>();
        List<SysUser> userList = userMapper.selectByIds(userIds);
        userList.forEach(e -> {
            userMap.put(e.getUserId(), e);
            deptIds.add(e.getDeptId());
        });
        if (!deptIds.isEmpty()) {
            deptService.selectDeptByIds(deptIds)
                .forEach(e -> deptMap.put(e.getDeptId(), e.getDeptName()));
        }
        return TableDataInfo.build(page.convert(e -> {
            ProjectMemberListVo vo = new ProjectMemberListVo();
            SysUser user = userMap.get(e.getUserId());
            if (user == null) {
                return null;
            }
            vo.setId(user.getUserId());
            vo.setName(user.getNickName());
            vo.setPhoneNumber(user.getPhonenumber());
            vo.setDept(deptMap.get(user.getDeptId()));
            vo.setTime(user.getCreateTime());
            return vo;
        }));
    }


    @Override
    public TableDataInfo<ProjectOnDocumentVo> listOnDocument(ProjectOnDocumentBo bo, PageQuery pageQuery) {
        LambdaQueryWrapper<Project> wrapper = buildQueryOnDocumentWrapper(bo);
        IPage<Project> page = baseMapper.selectPage(pageQuery.build(), wrapper);
        return TableDataInfo.build(page.convert(e -> {
            ProjectOnDocumentVo vo = new ProjectOnDocumentVo();
            vo.setId(e.getId());
            vo.setCode(e.getCode());
            vo.setName(e.getName());
            vo.setLanguage(e.getLanguage());
            vo.setType(e.getType());
            vo.setStatus(ProjectStatusEnum.getLabel(e.getStatus()));
            vo.setStartTime(e.getStartTime());
            vo.setEndTime(e.getEndTime());
            vo.setCreateTime(e.getCreateTime());
            vo.setUpdateTime(e.getUpdateTime());
            return vo;
        }));
    }

    @Override
    public boolean inviteCenterMember(ProjectInviteCenterMemberBo bo) {
        List<SysUserFolder> userFolder = new ArrayList<>();
        bo.getUserIds().forEach(e -> {
            SysUserFolder entity = new SysUserFolder();
            entity.setUserId(e);
            entity.setFolderId(bo.getFolderId());
            userFolder.add(entity);
        });
        return userFolderMapper.insertBatch(userFolder);
    }

    @Override
    public TableDataInfo<ProjectMemberNotInCenterVo> queryMemberNotInCenter(Long projectId, Long folderId, String name, PageQuery pageQuery) {
        // TODO 排除已在中心中的人
        List<Long> userIdsInFolder = new ArrayList<>();
        // TODO 只能是项目中的人
        List<Long> userIdsInProject = new ArrayList<>();
        userProjectsMapper.selectList(
            Wrappers.lambdaQuery(SysUserProjects.class)
                .and(wrapper -> wrapper
                    .eq(SysUserProjects::getProjects, "*")
                    .or()
                    .apply(DataBaseHelper.findInSet(projectId, "projects")))
                .orderByDesc(SysUserProjects::getUserId)
        ).forEach(e -> userIdsInProject.add(e.getUserId()));
        if (userIdsInProject.isEmpty()) {
            return TableDataInfo.build();
        }
        userFolderMapper.selectList(Wrappers.lambdaQuery(SysUserFolder.class).eq(SysUserFolder::getFolderId, folderId))
            .forEach(e -> userIdsInFolder.add(e.getUserId()));
        IPage<SysUser> page = userMapper.selectPage(
            pageQuery.build(),
            Wrappers.lambdaQuery(SysUser.class)
                .notIn(!userIdsInFolder.isEmpty(), SysUser::getUserId, userIdsInFolder)
                .in(SysUser::getUserId, userIdsInProject)
                .like(StringUtils.isNotBlank(name), SysUser::getNickName, name)
        );
        if (page.getRecords().isEmpty()) {
            return TableDataInfo.build();
        }
        List<Long> deptIds = new ArrayList<>();
        Map<Long, String> deptMap = new HashMap<>();
        page.getRecords().forEach(e -> deptIds.add(e.getDeptId()));
        deptService.selectDeptByIds(deptIds).forEach(e -> deptMap.put(e.getDeptId(), e.getDeptName()));
        return TableDataInfo.build(page.convert(e -> {
            ProjectMemberNotInCenterVo vo = new ProjectMemberNotInCenterVo();
            vo.setId(e.getUserId());
            vo.setName(e.getNickName());
            vo.setDept(deptMap.get(e.getDeptId()));
            vo.setPhoneNumber(e.getPhonenumber());
            return vo;
        }));
    }

    @Override
    public TableDataInfo<ProjectInDashboardWorkbenchVo> queryPageListOnDashboardWorkbench(ProjectListOnDashboardWorkbenchBo bo, PageQuery pageQuery) {
        return TableDataInfo.build();
    }

    private LambdaQueryWrapper<Folder> buildQueryProjectCenterWrapper(ProjectCenterListBo bo) {
        return Wrappers.lambdaQuery(Folder.class)
            .like(StringUtils.isNotEmpty(bo.getName()), Folder::getName, bo.getName())
            .orderByDesc(Folder::getId);
    }

    private LambdaQueryWrapper<Project> buildQueryOnDocumentWrapper(ProjectOnDocumentBo bo) {
        Map<String, Object> params = bo.getParams();
        LambdaQueryWrapper<Project> lqw = Wrappers.lambdaQuery();
        lqw.orderByDesc(Project::getId);
        lqw.like(StringUtils.isNotBlank(bo.getCode()), Project::getCode, bo.getCode());
        lqw.like(StringUtils.isNotBlank(bo.getName()), Project::getName, bo.getName());
        lqw.eq(StringUtils.isNotBlank(bo.getLanguage()), Project::getLanguage, bo.getLanguage());
        lqw.eq(StringUtils.isNotBlank(bo.getType()), Project::getType, bo.getType());
        lqw.eq(bo.getStatus() != null, Project::getStatus, bo.getStatus());
        lqw.between(params.get("beginStartTime") != null && params.get("endStartTime") != null,
            Project::getStartTime, params.get("beginStartTime"), params.get("endStartTime"));
        lqw.between(params.get("beginEndTime") != null && params.get("endEndTime") != null,
            Project::getEndTime, params.get("beginEndTime"), params.get("endEndTime"));
        lqw.between(params.get("beginCreateTime") != null && params.get("endCreateTime") != null,
            Project::getCreateTime, params.get("beginCreateTime"), params.get("endCreateTime"));
        lqw.between(params.get("beginUpdateTime") != null && params.get("endUpdateTime") != null,
            Project::getUpdateTime, params.get("beginUpdateTime"), params.get("endUpdateTime"));

        // TODO 只有拥有该项目数据权限的人才能够在列表中看到该项目
        String projects = userProjectsMapper.selectOne(
            Wrappers.lambdaQuery(SysUserProjects.class)
                .eq(SysUserProjects::getUserId, LoginHelper.getUserId())
        ).getProjects();
        if (projects.isEmpty()) {
            lqw.in(Project::getId, List.of(-1L));
        } else if (!projects.equals("*")) {
            lqw.in(Project::getId, Arrays.stream(projects.split(",")).map(Long::valueOf).toList());
        }

        return lqw;
    }
}
