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

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.weekly.vo.WeeklyReportPageReqVO;
import com.njcn.rdms.module.project.dal.dataobject.workreport.weekly.WeeklyReportDO;
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 WeeklyReportMapper extends BaseMapperX<WeeklyReportDO> {

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

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

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

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

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

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

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

    default int updateByIdAndStatus(WeeklyReportDO update, Long id, String fromStatus) {
        return update(update, new LambdaQueryWrapperX<WeeklyReportDO>()
                .eq(WeeklyReportDO::getId, id)
                .eq(WeeklyReportDO::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<WeeklyReportDO>()
                .set(WeeklyReportDO::getReporterDeptName, reporterDeptName)
                .set(WeeklyReportDO::getReporterPostName, reporterPostName)
                .set(WeeklyReportDO::getSupervisorUserId, supervisorUserId)
                .set(WeeklyReportDO::getSupervisorName, supervisorName)
                .set(WeeklyReportDO::getStatusCode, toStatus)
                .set(WeeklyReportDO::getSubmitTime, submitTime)
                .set(WeeklyReportDO::getApprovalTime, null)
                .set(WeeklyReportDO::getApprovalComment, null)
                .set(WeeklyReportDO::getLastStatusReason, null)
                .set(WeeklyReportDO::getUpdateTime, submitTime)
                .set(WeeklyReportDO::getUpdater, updater)
                .eq(WeeklyReportDO::getId, id)
                .eq(WeeklyReportDO::getStatusCode, fromStatus));
    }

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

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

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

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

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