package com.ningdatech.pmapi.expert.manage;

import cn.hutool.json.JSONUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.ningdatech.basic.exception.BizException;
import com.ningdatech.basic.util.CollUtils;
import com.ningdatech.cache.lock.DistributedLock;
import com.ningdatech.pmapi.expert.model.dto.ReviewTemplateOptionDTO;
import com.ningdatech.pmapi.expert.model.entity.ExpertReview;
import com.ningdatech.pmapi.expert.model.req.ExpertReviewDetailReq;
import com.ningdatech.pmapi.expert.model.vo.ExpertReviewDetailVO;
import com.ningdatech.pmapi.expert.service.IExpertReviewService;
import com.ningdatech.pmapi.user.util.LoginUserUtil;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Component;

import java.util.List;

/**
 * <p>
 * ExpertReviewManage
 * </p>
 *
 * @author WendyYang
 * @since 14:25 2023/2/15
 */
@Component
@RequiredArgsConstructor
public class ExpertReviewManage {

    private final IExpertReviewService expertReviewService;
    private final DistributedLock distributedLock;

    private static final String EXPERT_REVIEW_KEY = "expert_review:";

    private String buildExpertReviewKey(Long projectId, Long expertId) {
        return EXPERT_REVIEW_KEY + projectId + ":" + expertId;
    }

    private ExpertReviewDetailVO buildExpertReviewDetail(ExpertReview review) {
        return ExpertReviewDetailVO.builder()
                .reviewResult(review.getReviewResult())
                .creator(review.getCreator())
                .projectId(review.getProjectId())
                .templateId(review.getTemplateId())
                .otherAdvice(review.getOtherAdvice())
                .isFinal(review.getIsFinal())
                .createOn(review.getCreateOn())
                .attachFileId(review.getAttachFileId())
                .reviewTemplateOptions(JSONUtil.toList(review.getContent(), ReviewTemplateOptionDTO.class))
                .build();
    }

    public void expertReview(ExpertReviewDetailReq req) {
        Long userId = LoginUserUtil.getUserId();
        Long projectId = req.getProjectId();
        String expertReviewKey = buildExpertReviewKey(projectId, userId);
        if (!distributedLock.lock(expertReviewKey)) {
            throw BizException.wrap("保存评审意见失败，请重试");
        }
        try {
            List<ExpertReview> reviews = expertReviewService.listByProjectIdAndExpertId(projectId, userId);
            if (req.getIsFinal()) {
                // TODO 判断所有专家是否都已评价
                if (reviews.isEmpty()) {
                    throw BizException.wrap("请先填写个人评审意见");
                }
                if (reviews.size() > 1) {
                    throw BizException.wrap("不可重复填写最终评审意见");
                }
            } else {
                if (!reviews.isEmpty()) {
                    throw BizException.wrap("不可重复填写评审意见");
                }
            }
            ExpertReview review = new ExpertReview();
            review.setReviewResult(req.getReviewResult());
            review.setContent(JSONUtil.toJsonStr(req.getReviewTemplateOptions()));
            review.setProjectId(req.getProjectId());
            review.setTemplateId(req.getTemplateId());
            review.setOtherAdvice(req.getOtherAdvice());
            review.setAttachFileId(req.getAttachFileId());
            review.setIsFinal(req.getIsFinal());
            review.setCreator(LoginUserUtil.getUsername());
            expertReviewService.save(review);
        } finally {
            distributedLock.releaseLock(expertReviewKey);
        }
    }

    public ExpertReviewDetailVO getExpertReviewDetail(Long projectId, Long userId) {
        List<ExpertReview> reviews = expertReviewService.listByProjectIdAndExpertId(projectId, userId);
        reviews.removeIf(ExpertReview::getIsFinal);
        if (reviews.isEmpty()) {
            throw BizException.wrap("评审记录不存在");
        }
        return buildExpertReviewDetail(reviews.get(0));
    }

    public List<ExpertReviewDetailVO> listForGroupLeader(Long projectId, Long userId) {
        LambdaQueryWrapper<ExpertReview> query = Wrappers.lambdaQuery(ExpertReview.class);
        query.eq(ExpertReview::getProjectId, projectId);
        query.ne(ExpertReview::getCreateBy, userId);
        query.orderByDesc(ExpertReview::getCreateOn);
        List<ExpertReview> reviews = expertReviewService.list(query);
        return CollUtils.convert(reviews, this::buildExpertReviewDetail);
    }

}
