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.LocalDate;
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 List<MonthlyReportDO> selectListByReporterIdsAndPeriodKey(Collection<Long> reporterIds, String periodKey,
            Collection<String> allowedStatusCodes) {
        if (reporterIds == null || reporterIds.isEmpty() || !StringUtils.hasText(periodKey)) {
            return List.of();
        }
        LambdaQueryWrapperX<MonthlyReportDO> wrapper = new LambdaQueryWrapperX<MonthlyReportDO>()
                .in(MonthlyReportDO::getReporterId, reporterIds)
                .eq(MonthlyReportDO::getPeriodKey, periodKey);
        if (allowedStatusCodes != null) {
            if (allowedStatusCodes.isEmpty()) {
                return List.of();
            }
            wrapper.in(MonthlyReportDO::getStatusCode, allowedStatusCodes);
        }
        return selectList(wrapper);
    }

    /**
     * 按报告人 ID 列表与周期日期区间查询月报（periodStartDate 落在 [startDate, endDate] 内）。
     */
    default List<MonthlyReportDO> selectListByReporterIdsAndPeriodDateRange(Collection<Long> reporterIds,
            LocalDate startDate, LocalDate endDate,
            Collection<String> allowedStatusCodes) {
        if (reporterIds == null || reporterIds.isEmpty()) {
            return List.of();
        }
        LambdaQueryWrapperX<MonthlyReportDO> wrapper = new LambdaQueryWrapperX<MonthlyReportDO>()
                .in(MonthlyReportDO::getReporterId, reporterIds)
                .geIfPresent(MonthlyReportDO::getPeriodStartDate, startDate)
                .leIfPresent(MonthlyReportDO::getPeriodStartDate, endDate);
        if (allowedStatusCodes != null) {
            if (allowedStatusCodes.isEmpty()) {
                return List.of();
            }
            wrapper.in(MonthlyReportDO::getStatusCode, allowedStatusCodes);
        }
        return selectList(wrapper);
    }

    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> selectReporterPage(Collection<Long> reporterIds, MonthlyReportPageReqVO reqVO,
            Collection<String> allowedStatusCodes) {
        if (reporterIds == null || reporterIds.isEmpty()
                || (allowedStatusCodes != null && allowedStatusCodes.isEmpty())) {
            return new PageResult<>(List.of(), 0L);
        }
        LambdaQueryWrapperX<MonthlyReportDO> wrapper = buildPageQuery(reqVO)
                .in(MonthlyReportDO::getReporterId, reporterIds)
                .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 updateByIdAndStatusAndSignOffStatus(MonthlyReportDO update, Long id, String fromStatus,
            String fromSignOffStatus) {
        return update(update, new LambdaQueryWrapperX<MonthlyReportDO>()
                .eq(MonthlyReportDO::getId, id)
                .eq(MonthlyReportDO::getStatusCode, fromStatus)
                .eq(MonthlyReportDO::getSignOffStatus, fromSignOffStatus));
    }

    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));
    }

    default List<MonthlyReportDO> selectListByPendingSubmitReminder(LocalDateTime cutoffTime,
            Collection<String> statusCodes) {
        if (cutoffTime == null || statusCodes == null || statusCodes.isEmpty()) {
            return List.of();
        }
        return selectList(new LambdaQueryWrapperX<MonthlyReportDO>()
                .in(MonthlyReportDO::getStatusCode, statusCodes)
                .le(MonthlyReportDO::getCreateTime, cutoffTime)
                .orderByAsc(MonthlyReportDO::getCreateTime)
                .orderByAsc(MonthlyReportDO::getId));
    }

    private LambdaQueryWrapperX<MonthlyReportDO> buildPageQuery(MonthlyReportPageReqVO reqVO) {
        LambdaQueryWrapperX<MonthlyReportDO> wrapper = new LambdaQueryWrapperX<MonthlyReportDO>()
                .eqIfPresent(MonthlyReportDO::getStatusCode, reqVO.getStatusCode())
                .eqIfPresent(MonthlyReportDO::getSignOffStatus, reqVO.getSignOffStatus())
                .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;
    }
}
