package com.njcn.rdms.module.project.dal.mysql.workreport.monthly;

import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.njcn.rdms.framework.common.pojo.PageResult;
import com.njcn.rdms.framework.mybatis.core.mapper.BaseMapperX;
import com.njcn.rdms.framework.mybatis.core.query.LambdaQueryWrapperX;
import com.njcn.rdms.module.project.constant.WorkReportConstants;
import com.njcn.rdms.module.project.controller.admin.workreport.monthly.vo.MonthlyReportPageReqVO;
import com.njcn.rdms.module.project.dal.dataobject.workreport.monthly.MonthlyReportDO;
import org.apache.ibatis.annotations.Mapper;
import org.springframework.util.StringUtils;

import java.time.LocalDateTime;
import java.util.Collection;
import java.util.List;

@Mapper
public interface MonthlyReportMapper extends BaseMapperX<MonthlyReportDO> {

    default MonthlyReportDO selectByReporterIdAndPeriodKey(Long reporterId, String periodKey) {
        return selectOne(new LambdaQueryWrapperX<MonthlyReportDO>()
                .eq(MonthlyReportDO::getReporterId, reporterId)
                .eq(MonthlyReportDO::getPeriodKey, periodKey));
    }

    default PageResult<MonthlyReportDO> selectReporterPage(Long reporterId, MonthlyReportPageReqVO reqVO) {
        return selectReporterPage(reporterId, reqVO, null);
    }

    default PageResult<MonthlyReportDO> selectReporterPage(Long reporterId, MonthlyReportPageReqVO reqVO,
                                                           Collection<String> allowedStatusCodes) {
        if (allowedStatusCodes != null && allowedStatusCodes.isEmpty()) {
            return new PageResult<>(List.of(), 0L);
        }
        LambdaQueryWrapperX<MonthlyReportDO> wrapper = buildPageQuery(reqVO)
                .eq(MonthlyReportDO::getReporterId, reporterId)
                .orderByDesc(MonthlyReportDO::getPeriodStartDate)
                .orderByDesc(MonthlyReportDO::getId);
        if (allowedStatusCodes != null) {
            wrapper.in(MonthlyReportDO::getStatusCode, allowedStatusCodes);
        }
        return selectPage(reqVO, wrapper);
    }

    default PageResult<MonthlyReportDO> selectApprovalPage(Long supervisorUserId, MonthlyReportPageReqVO reqVO) {
        LambdaQueryWrapperX<MonthlyReportDO> wrapper = buildPageQuery(reqVO)
                .eq(MonthlyReportDO::getSupervisorUserId, supervisorUserId)
                .eq(MonthlyReportDO::getStatusCode, WorkReportConstants.STATUS_PENDING_APPROVAL)
                .orderByDesc(MonthlyReportDO::getSubmitTime)
                .orderByDesc(MonthlyReportDO::getId);
        return selectPage(reqVO, wrapper);
    }

    default int updateByIdAndStatus(MonthlyReportDO update, Long id, String fromStatus) {
        return update(update, new LambdaQueryWrapperX<MonthlyReportDO>()
                .eq(MonthlyReportDO::getId, id)
                .eq(MonthlyReportDO::getStatusCode, fromStatus));
    }

    default int updateSubmitFieldsByIdAndStatus(Long id, String fromStatus, String reporterDeptName,
                                                String reporterPostName, Long supervisorUserId,
                                                String supervisorName, String toStatus, LocalDateTime submitTime,
                                                String updater) {
        return update(null, new LambdaUpdateWrapper<MonthlyReportDO>()
                .set(MonthlyReportDO::getReporterDeptName, reporterDeptName)
                .set(MonthlyReportDO::getReporterPostName, reporterPostName)
                .set(MonthlyReportDO::getSupervisorUserId, supervisorUserId)
                .set(MonthlyReportDO::getSupervisorName, supervisorName)
                .set(MonthlyReportDO::getStatusCode, toStatus)
                .set(MonthlyReportDO::getSubmitTime, submitTime)
                .set(MonthlyReportDO::getApprovalTime, null)
                .set(MonthlyReportDO::getApprovalComment, null)
                .set(MonthlyReportDO::getLastStatusReason, null)
                .set(MonthlyReportDO::getUpdateTime, submitTime)
                .set(MonthlyReportDO::getUpdater, updater)
                .eq(MonthlyReportDO::getId, id)
                .eq(MonthlyReportDO::getStatusCode, fromStatus));
    }

    default int updateApprovalFieldsByIdAndStatus(Long id, String fromStatus, String toStatus,
                                                  LocalDateTime approvalTime, String approvalComment,
                                                  String lastStatusReason, String updater) {
        return update(null, new LambdaUpdateWrapper<MonthlyReportDO>()
                .set(MonthlyReportDO::getStatusCode, toStatus)
                .set(MonthlyReportDO::getApprovalTime, approvalTime)
                .set(MonthlyReportDO::getApprovalComment, approvalComment)
                .set(MonthlyReportDO::getLastStatusReason, lastStatusReason)
                .set(MonthlyReportDO::getUpdateTime, approvalTime)
                .set(MonthlyReportDO::getUpdater, updater)
                .eq(MonthlyReportDO::getId, id)
                .eq(MonthlyReportDO::getStatusCode, fromStatus));
    }

    default int updateByIdAndStatusesAndReporterId(MonthlyReportDO update, Long id, Collection<String> statuses,
                                                   Long reporterId) {
        return update(update, new LambdaQueryWrapperX<MonthlyReportDO>()
                .eq(MonthlyReportDO::getId, id)
                .eq(MonthlyReportDO::getReporterId, reporterId)
                .in(MonthlyReportDO::getStatusCode, statuses));
    }

    default int deleteByIdAndStatusesAndReporterId(Long id, Collection<String> statuses, Long reporterId) {
        return delete(new LambdaQueryWrapperX<MonthlyReportDO>()
                .eq(MonthlyReportDO::getId, id)
                .eq(MonthlyReportDO::getReporterId, reporterId)
                .in(MonthlyReportDO::getStatusCode, statuses));
    }

    private LambdaQueryWrapperX<MonthlyReportDO> buildPageQuery(MonthlyReportPageReqVO reqVO) {
        LambdaQueryWrapperX<MonthlyReportDO> wrapper = new LambdaQueryWrapperX<MonthlyReportDO>()
                .eqIfPresent(MonthlyReportDO::getStatusCode, reqVO.getStatusCode())
                .betweenIfPresent(MonthlyReportDO::getPeriodStartDate, reqVO.getPeriodStartDate())
                .betweenIfPresent(MonthlyReportDO::getSubmitTime, reqVO.getSubmitTime());
        if (StringUtils.hasText(reqVO.getKeyword())) {
            wrapper.and(w -> w.like(MonthlyReportDO::getPeriodLabel, reqVO.getKeyword())
                    .or()
                    .like(MonthlyReportDO::getReporterName, reqVO.getKeyword())
                    .or()
                    .like(MonthlyReportDO::getSupervisorName, reqVO.getKeyword()));
        }
        return wrapper;
    }
}
