package cn.ey.biz.module.system.service.code;

import cn.ey.biz.common.pojo.PageParam;
import cn.ey.biz.common.pojo.PageResult;
import cn.ey.biz.framework.mybatis.core.query.LambdaQueryWrapperX;
import cn.ey.biz.module.system.api.code.dto.CodeProjectDTO;
import cn.ey.biz.module.system.controller.admin.code.vo.CodeProjectVO;
import cn.ey.biz.module.system.controller.admin.code.vo.HistoryVO;
import cn.ey.biz.module.system.convert.code.CodeProjectConvert;
import cn.ey.biz.module.system.dal.dataobject.code.CodeProjectDO;
import cn.ey.biz.module.system.dal.dataobject.user.AdminUserDO;
import cn.ey.biz.module.system.dal.mapper.code.CodeProjectMapper;
import cn.ey.biz.module.system.service.user.AdminUserService;
import cn.hutool.core.collection.CollectionUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.validation.annotation.Validated;

import javax.annotation.Resource;
import java.text.SimpleDateFormat;
import java.util.List;
import java.util.stream.Collectors;

import static cn.ey.biz.common.exception.util.ServiceExceptionUtil.exception;
import static cn.ey.biz.module.system.enums.ErrorCodeConstants.CODE_RULE_PROJECT_CODE;
import static cn.ey.biz.module.system.enums.ErrorCodeConstants.CODE_RULE_PROJECT_NAME_ONE;

@Service
@Validated
@Slf4j
public class CodeProjectServiceImpl implements CodeProjectService {

    @Resource
    private CodeProjectMapper codeProjectMapper;

    @Resource
    private AdminUserService adminUserService;

    @Override
    @Transactional
    public Long submitProject(CodeProjectVO codeProjectVO) {
        List<CodeProjectVO.Code> codes = codeProjectVO.getAssurance().getCodes();
        if (CollectionUtil.isNotEmpty(codes)) {
            boolean uniqueCode = codes.stream()
                    .collect(Collectors.groupingBy(p -> p.getCode() + ":" + p.getPrefix()))
                    .values().stream()
                    .anyMatch(group -> group.size() > 1);
            if (uniqueCode) {
                throw exception(CODE_RULE_PROJECT_CODE);
            }
        }

        List<CodeProjectVO.Item> operations = codeProjectVO.getConsulting().getPrefix().get(0).getOperations();
        boolean onePrefix = operations.stream()
                .collect(Collectors.groupingBy(p -> p.getName() + ":" + p.getRelation().get(0).getName()))
                .values().stream()
                .anyMatch(group -> group.size() > 1);
        if (onePrefix) {
            throw exception(CODE_RULE_PROJECT_NAME_ONE);
        }
        CodeProjectDO codeProjectDO = CodeProjectConvert.INSTANCE.vo2Do(codeProjectVO);

        LambdaUpdateWrapper<CodeProjectDO> updateWrapper = new LambdaUpdateWrapper<>();
        updateWrapper.eq(CodeProjectDO::getActive, 1);
        updateWrapper.set(CodeProjectDO::getActive, 0);
        codeProjectMapper.update(null, updateWrapper);

        codeProjectDO.setActive(1);
        codeProjectMapper.insert(codeProjectDO);
        return codeProjectDO.getId();
    }

    @Override
    public PageResult<HistoryVO> getHistory(PageParam pageParam) {
        PageResult<CodeProjectDO> pageDo = codeProjectMapper.selectPage(pageParam,
                new LambdaQueryWrapperX<CodeProjectDO>().orderByDesc(CodeProjectDO::getCreateTime));
        PageResult<HistoryVO> pageHistory = new PageResult<>();
        pageHistory.setList(pageDo.getList().stream().map(doo -> {
            HistoryVO vo = CodeProjectConvert.INSTANCE.do2History(doo);
            String updater = doo.getUpdater();
            AdminUserDO user = adminUserService.getUser(Long.valueOf(updater));
            if (user != null) {
                vo.setUpdateUser(user.getUsername());
            }
            return vo;
        }).collect(Collectors.toList()));
        pageHistory.setTotal(pageDo.getTotal());
        return pageHistory;
    }

    @Override
    public CodeProjectDTO getCodeProject(Long ver) {
        LambdaQueryWrapper<CodeProjectDO> query = new LambdaQueryWrapper<>();
        if (ver != null) {
            query.eq(CodeProjectDO::getId, ver);
        } else {
            query.eq(CodeProjectDO::getActive, 1);
        }
        CodeProjectDO doo = codeProjectMapper.selectOne(query);
        CodeProjectDTO dto = CodeProjectConvert.INSTANCE.do2Dto(doo);

        SimpleDateFormat sdf = new SimpleDateFormat("yyyy.MM.dd HH:mm:ss");
        dto.setDate(sdf.format(doo.getCreateTime()));
        AdminUserDO user = adminUserService.getUser(Long.valueOf(doo.getUpdater()));
        if (user != null) {
            dto.setUpdater(user.getUsername());
        }
        return dto;
    }

    @Override
    public void revertHistory(Long ver) {
        LambdaUpdateWrapper<CodeProjectDO> deleteOld = new LambdaUpdateWrapper<>();
        deleteOld.eq(CodeProjectDO::getActive, 1);
        deleteOld.set(CodeProjectDO::getActive, 0);
        codeProjectMapper.update(null, deleteOld);

        LambdaUpdateWrapper<CodeProjectDO> addNew = new LambdaUpdateWrapper<>();
        addNew.eq(CodeProjectDO::getId, ver);
        addNew.set(CodeProjectDO::getActive, 1);
        codeProjectMapper.update(null, addNew);
    }
}
