package cn.iocoder.yudao.module.pms.dal.mysql.iotrydailyreport;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.ObjUtil;
import cn.hutool.core.util.StrUtil;
import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX;
import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX;
import cn.iocoder.yudao.framework.tenant.core.aop.TenantIgnore;
import cn.iocoder.yudao.module.pms.controller.admin.iotrydailyreport.vo.IotRyDailyReportPageReqVO;
import cn.iocoder.yudao.module.pms.controller.admin.iotrydailyreport.vo.IotRyDailyReportTaskCountVO;
import cn.iocoder.yudao.module.pms.controller.admin.maintain.vo.IotMaintainPageReqVO;
import cn.iocoder.yudao.module.pms.controller.admin.stat.vo.AllOrderResp;
import cn.iocoder.yudao.module.pms.dal.dataobject.iotrydailyreport.IotRyDailyReportDO;
import com.baomidou.mybatisplus.core.metadata.IPage;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Param;
import org.apache.ibatis.annotations.Select;

import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.Collection;
import java.util.List;
import java.util.Objects;

/**
 * 瑞鹰日报 Mapper
 *
 * @author ruiqi
 */
@Mapper
public interface IotRyDailyReportMapper extends BaseMapperX<IotRyDailyReportDO> {

    default List<IotRyDailyReportDO> dailyReports(IotRyDailyReportPageReqVO reqVO) {
        // 获取查询参数中的 projectClassification 值
        String projectClassification = reqVO.getProjectClassification();
        LambdaQueryWrapperX<IotRyDailyReportDO> queryWrapper = new LambdaQueryWrapperX<IotRyDailyReportDO>();
        // 创建查询包装器
        queryWrapper
                // .eqIfPresent(IotRyDailyReportDO::getDeptId, reqVO.getDeptId())
                .inIfPresent(IotRyDailyReportDO::getDeptId, reqVO.getDeptIds())
                .eqIfPresent(IotRyDailyReportDO::getProjectId, reqVO.getProjectId())
                .inIfPresent(IotRyDailyReportDO::getProjectId, reqVO.getProjectIds())
                .eqIfPresent(IotRyDailyReportDO::getTaskId, reqVO.getTaskId())
                .inIfPresent(IotRyDailyReportDO::getTaskId, reqVO.getTaskIds())
                .eqIfPresent(IotRyDailyReportDO::getRelocationDays, reqVO.getRelocationDays())
                .betweenIfPresent(IotRyDailyReportDO::getLatestWellDoneTime, reqVO.getLatestWellDoneTime())
                .eqIfPresent(IotRyDailyReportDO::getCurrentDepth, reqVO.getCurrentDepth())
                .eqIfPresent(IotRyDailyReportDO::getDailyFootage, reqVO.getDailyFootage())
                .eqIfPresent(IotRyDailyReportDO::getMonthlyFootage, reqVO.getMonthlyFootage())
                .eqIfPresent(IotRyDailyReportDO::getAnnualFootage, reqVO.getAnnualFootage())
                .eqIfPresent(IotRyDailyReportDO::getDailyPowerUsage, reqVO.getDailyPowerUsage())
                .eqIfPresent(IotRyDailyReportDO::getMonthlyPowerUsage, reqVO.getMonthlyPowerUsage())
                .eqIfPresent(IotRyDailyReportDO::getDailyFuel, reqVO.getDailyFuel())
                .eqIfPresent(IotRyDailyReportDO::getMonthlyFuel, reqVO.getMonthlyFuel())
                .betweenIfPresent(IotRyDailyReportDO::getNonProductionTime, reqVO.getNonProductionTime())
                .eqIfPresent(IotRyDailyReportDO::getRyNptReason, reqVO.getRyNptReason())
                .betweenIfPresent(IotRyDailyReportDO::getConstructionStartDate, reqVO.getConstructionStartDate())
                .betweenIfPresent(IotRyDailyReportDO::getConstructionEndDate, reqVO.getConstructionEndDate())
                .eqIfPresent(IotRyDailyReportDO::getProductionStatus, reqVO.getProductionStatus())
                .eqIfPresent(IotRyDailyReportDO::getNextPlan, reqVO.getNextPlan())
                .eqIfPresent(IotRyDailyReportDO::getRigStatus, reqVO.getRigStatus())
                .eqIfPresent(IotRyDailyReportDO::getPersonnel, reqVO.getPersonnel())
                .eqIfPresent(IotRyDailyReportDO::getMudDensity, reqVO.getMudDensity())
                .eqIfPresent(IotRyDailyReportDO::getMudViscosity, reqVO.getMudViscosity())
                .eqIfPresent(IotRyDailyReportDO::getLateralLength, reqVO.getLateralLength())
                .eqIfPresent(IotRyDailyReportDO::getWellInclination, reqVO.getWellInclination())
                .eqIfPresent(IotRyDailyReportDO::getAzimuth, reqVO.getAzimuth())
                .eqIfPresent(IotRyDailyReportDO::getExtProperty, reqVO.getExtProperty())
                .eqIfPresent(IotRyDailyReportDO::getSort, reqVO.getSort())
                .eqIfPresent(IotRyDailyReportDO::getRemark, reqVO.getRemark())
                .eqIfPresent(IotRyDailyReportDO::getStatus, reqVO.getStatus())
                .eqIfPresent(IotRyDailyReportDO::getProcessInstanceId, reqVO.getProcessInstanceId())
                .eqIfPresent(IotRyDailyReportDO::getAuditStatus, reqVO.getAuditStatus())
                .betweenIfPresent(IotRyDailyReportDO::getCreateTime, reqVO.getCreateTime())
                .orderByDesc(IotRyDailyReportDO::getCreateTime)
                .orderByAsc(IotRyDailyReportDO::getId);

        // 处理 statuses 条件：当 statuses 有值时，查询 rigStatus 或 repairStatus 不在 statuses 中的数据
        Collection<String> statuses = reqVO.getStatuses();
        if (CollUtil.isNotEmpty(statuses)) { // 判断集合非空
            queryWrapper.and(wrapper -> wrapper
                    .notIn(IotRyDailyReportDO::getRigStatus, statuses) // rigStatus 不在集合中
                    .or() // 或
                    .notIn(IotRyDailyReportDO::getRepairStatus, statuses) // repairStatus 不在集合中
            );
        }

        // 单独处理 projectClassification 条件
        if ("1".equals(projectClassification)) {
            // 当值为 "1" 时，查询 project_classification 为 "1" 或空字符串的记录
            queryWrapper.and(wrapper -> wrapper
                    .eq(IotRyDailyReportDO::getProjectClassification, "1")
                    .or().eq(IotRyDailyReportDO::getProjectClassification, "")
            );
        } else {
            // 其他情况：有值则精确匹配，无值则不添加条件（保持原逻辑）
            queryWrapper.eqIfPresent(IotRyDailyReportDO::getProjectClassification, projectClassification);
        }

        return selectList(queryWrapper);
    }

    default PageResult<IotRyDailyReportDO> selectPage(IotRyDailyReportPageReqVO reqVO) {
        // 1. 构建基础查询（不含 projectIds/taskIds 的 IN 条件）
        LambdaQueryWrapperX<IotRyDailyReportDO> queryWrapper = buildBaseQuery(reqVO);
        // 2. 根据 searchKey 决定 projectIds/taskIds 的组合方式
        if (StrUtil.isNotBlank(reqVO.getSearchKey())) {
            // 移动端：使用 OR
            Collection<Long> projectIds = reqVO.getProjectIds();
            Collection<Long> taskIds = reqVO.getTaskIds();
            boolean hasProject = CollUtil.isNotEmpty(projectIds);
            boolean hasTask = CollUtil.isNotEmpty(taskIds);
            if (hasProject || hasTask) {
                queryWrapper.and(wq -> {
                    if (hasProject) {
                        wq.in(IotRyDailyReportDO::getProjectId, projectIds);
                    }
                    if (hasProject && hasTask) {
                        wq.or();
                    }
                    if (hasTask) {
                        wq.in(IotRyDailyReportDO::getTaskId, taskIds);
                    }
                });
            }
        } else {
            // PC 端：使用 AND
            queryWrapper
                    .inIfPresent(IotRyDailyReportDO::getProjectId, reqVO.getProjectIds())
                    .inIfPresent(IotRyDailyReportDO::getTaskId, reqVO.getTaskIds());
        }

        // 获取查询参数中的 projectClassification 值
        String projectClassification = reqVO.getProjectClassification();
        // LambdaQueryWrapperX<IotRyDailyReportDO> queryWrapper = new LambdaQueryWrapperX<IotRyDailyReportDO>();
        // 创建查询包装器
        /* queryWrapper
                // .eqIfPresent(IotRyDailyReportDO::getDeptId, reqVO.getDeptId())
                .inIfPresent(IotRyDailyReportDO::getDeptId, reqVO.getDeptIds())
                .eqIfPresent(IotRyDailyReportDO::getProjectId, reqVO.getProjectId())
                .inIfPresent(IotRyDailyReportDO::getProjectId, reqVO.getProjectIds())
                .eqIfPresent(IotRyDailyReportDO::getTaskId, reqVO.getTaskId())
                .inIfPresent(IotRyDailyReportDO::getTaskId, reqVO.getTaskIds())
                .eqIfPresent(IotRyDailyReportDO::getRelocationDays, reqVO.getRelocationDays())
                .betweenIfPresent(IotRyDailyReportDO::getLatestWellDoneTime, reqVO.getLatestWellDoneTime())
                .eqIfPresent(IotRyDailyReportDO::getCurrentDepth, reqVO.getCurrentDepth())
                .eqIfPresent(IotRyDailyReportDO::getDailyFootage, reqVO.getDailyFootage())
                .eqIfPresent(IotRyDailyReportDO::getMonthlyFootage, reqVO.getMonthlyFootage())
                .eqIfPresent(IotRyDailyReportDO::getAnnualFootage, reqVO.getAnnualFootage())
                .eqIfPresent(IotRyDailyReportDO::getDailyPowerUsage, reqVO.getDailyPowerUsage())
                .eqIfPresent(IotRyDailyReportDO::getMonthlyPowerUsage, reqVO.getMonthlyPowerUsage())
                .eqIfPresent(IotRyDailyReportDO::getDailyFuel, reqVO.getDailyFuel())
                .eqIfPresent(IotRyDailyReportDO::getMonthlyFuel, reqVO.getMonthlyFuel())
                .betweenIfPresent(IotRyDailyReportDO::getNonProductionTime, reqVO.getNonProductionTime())
                .eqIfPresent(IotRyDailyReportDO::getRyNptReason, reqVO.getRyNptReason())
                .betweenIfPresent(IotRyDailyReportDO::getConstructionStartDate, reqVO.getConstructionStartDate())
                .betweenIfPresent(IotRyDailyReportDO::getConstructionEndDate, reqVO.getConstructionEndDate())
                .eqIfPresent(IotRyDailyReportDO::getProductionStatus, reqVO.getProductionStatus())
                .eqIfPresent(IotRyDailyReportDO::getNextPlan, reqVO.getNextPlan())
                .eqIfPresent(IotRyDailyReportDO::getRigStatus, reqVO.getRigStatus())
                .eqIfPresent(IotRyDailyReportDO::getPersonnel, reqVO.getPersonnel())
                .eqIfPresent(IotRyDailyReportDO::getMudDensity, reqVO.getMudDensity())
                .eqIfPresent(IotRyDailyReportDO::getMudViscosity, reqVO.getMudViscosity())
                .eqIfPresent(IotRyDailyReportDO::getLateralLength, reqVO.getLateralLength())
                .eqIfPresent(IotRyDailyReportDO::getWellInclination, reqVO.getWellInclination())
                .eqIfPresent(IotRyDailyReportDO::getAzimuth, reqVO.getAzimuth())
                .eqIfPresent(IotRyDailyReportDO::getExtProperty, reqVO.getExtProperty())
                .eqIfPresent(IotRyDailyReportDO::getSort, reqVO.getSort())
                .eqIfPresent(IotRyDailyReportDO::getRemark, reqVO.getRemark())
                .eqIfPresent(IotRyDailyReportDO::getStatus, reqVO.getStatus())
                .eqIfPresent(IotRyDailyReportDO::getProcessInstanceId, reqVO.getProcessInstanceId())
                .eqIfPresent(IotRyDailyReportDO::getAuditStatus, reqVO.getAuditStatus())
                .betweenIfPresent(IotRyDailyReportDO::getCreateTime, reqVO.getCreateTime())
                .orderByDesc(IotRyDailyReportDO::getCreateTime)
                .orderByAsc(IotRyDailyReportDO::getId); */

        // 处理 statuses 条件：当 statuses 有值时，查询 rigStatus 或 repairStatus 不在 statuses 中的数据
        Collection<String> statuses = reqVO.getStatuses();
        if (CollUtil.isNotEmpty(statuses)) { // 判断集合非空
            queryWrapper.and(wrapper -> wrapper
                    .notIn(IotRyDailyReportDO::getRigStatus, statuses) // rigStatus 不在集合中
                    .or() // 或
                    .notIn(IotRyDailyReportDO::getRepairStatus, statuses) // repairStatus 不在集合中
            );
        }

        // 单独处理 projectClassification 条件
        if ("1".equals(projectClassification)) {
            // 当值为 "1" 时，查询 project_classification 为 "1" 或空字符串的记录 钻井
            queryWrapper.and(wrapper -> wrapper
                    .eq(IotRyDailyReportDO::getProjectClassification, "1")
                    .or().eq(IotRyDailyReportDO::getProjectClassification, "")
            );
        } else {
            // 其他情况：有值则精确匹配，无值则不添加条件（保持原逻辑） 修井
            queryWrapper.eqIfPresent(IotRyDailyReportDO::getProjectClassification, projectClassification);
        }
        // 查询非生产时效
        if ("Y".equals(reqVO.getNonProductFlag())) {
            queryWrapper.and(wrapper -> wrapper
                    .gt(IotRyDailyReportDO::getAccidentTime, BigDecimal.ZERO)
                    .or()
                    .gt(IotRyDailyReportDO::getRepairTime, BigDecimal.ZERO)
                    .or()
                    .gt(IotRyDailyReportDO::getComplexityTime, BigDecimal.ZERO)
                    .or()
                    .gt(IotRyDailyReportDO::getRectificationTime, BigDecimal.ZERO)
                    .or()
                    .gt(IotRyDailyReportDO::getWaitingStopTime, BigDecimal.ZERO)
                    .or()
                    .gt(IotRyDailyReportDO::getPartyaDesign, BigDecimal.ZERO)
                    .or()
                    .gt(IotRyDailyReportDO::getPartyaPrepare, BigDecimal.ZERO)
                    .or()
                    .gt(IotRyDailyReportDO::getPartyaResource, BigDecimal.ZERO)
                    .or()
                    .gt(IotRyDailyReportDO::getOtherNptTime, BigDecimal.ZERO)
            );
        }

        return selectPage(reqVO, queryWrapper);
    }

    /**
     * 构建公共基础查询条件（不包含 projectIds/taskIds 的 IN，但保留精确 ID）
     */
    default LambdaQueryWrapperX<IotRyDailyReportDO> buildBaseQuery(IotRyDailyReportPageReqVO reqVO) {
        LambdaQueryWrapperX<IotRyDailyReportDO> wrapper = new LambdaQueryWrapperX<>();
        wrapper
                .inIfPresent(IotRyDailyReportDO::getDeptId, reqVO.getDeptIds())
                .eqIfPresent(IotRyDailyReportDO::getProjectId, reqVO.getProjectId())
                .eqIfPresent(IotRyDailyReportDO::getTaskId, reqVO.getTaskId())
                .eqIfPresent(IotRyDailyReportDO::getRelocationDays, reqVO.getRelocationDays())
                .betweenIfPresent(IotRyDailyReportDO::getLatestWellDoneTime, reqVO.getLatestWellDoneTime())
                .eqIfPresent(IotRyDailyReportDO::getCurrentDepth, reqVO.getCurrentDepth())
                .eqIfPresent(IotRyDailyReportDO::getDailyFootage, reqVO.getDailyFootage())
                .eqIfPresent(IotRyDailyReportDO::getMonthlyFootage, reqVO.getMonthlyFootage())
                .eqIfPresent(IotRyDailyReportDO::getAnnualFootage, reqVO.getAnnualFootage())
                .eqIfPresent(IotRyDailyReportDO::getDailyPowerUsage, reqVO.getDailyPowerUsage())
                .eqIfPresent(IotRyDailyReportDO::getMonthlyPowerUsage, reqVO.getMonthlyPowerUsage())
                .eqIfPresent(IotRyDailyReportDO::getDailyFuel, reqVO.getDailyFuel())
                .eqIfPresent(IotRyDailyReportDO::getMonthlyFuel, reqVO.getMonthlyFuel())
                .betweenIfPresent(IotRyDailyReportDO::getNonProductionTime, reqVO.getNonProductionTime())
                .eqIfPresent(IotRyDailyReportDO::getRyNptReason, reqVO.getRyNptReason())
                .betweenIfPresent(IotRyDailyReportDO::getConstructionStartDate, reqVO.getConstructionStartDate())
                .betweenIfPresent(IotRyDailyReportDO::getConstructionEndDate, reqVO.getConstructionEndDate())
                .eqIfPresent(IotRyDailyReportDO::getProductionStatus, reqVO.getProductionStatus())
                .eqIfPresent(IotRyDailyReportDO::getNextPlan, reqVO.getNextPlan())
                .eqIfPresent(IotRyDailyReportDO::getRigStatus, reqVO.getRigStatus())
                .eqIfPresent(IotRyDailyReportDO::getPersonnel, reqVO.getPersonnel())
                .eqIfPresent(IotRyDailyReportDO::getMudDensity, reqVO.getMudDensity())
                .eqIfPresent(IotRyDailyReportDO::getMudViscosity, reqVO.getMudViscosity())
                .eqIfPresent(IotRyDailyReportDO::getLateralLength, reqVO.getLateralLength())
                .eqIfPresent(IotRyDailyReportDO::getWellInclination, reqVO.getWellInclination())
                .eqIfPresent(IotRyDailyReportDO::getAzimuth, reqVO.getAzimuth())
                .eqIfPresent(IotRyDailyReportDO::getExtProperty, reqVO.getExtProperty())
                .eqIfPresent(IotRyDailyReportDO::getSort, reqVO.getSort())
                .eqIfPresent(IotRyDailyReportDO::getRemark, reqVO.getRemark())
                .eqIfPresent(IotRyDailyReportDO::getStatus, reqVO.getStatus())
                .eqIfPresent(IotRyDailyReportDO::getProcessInstanceId, reqVO.getProcessInstanceId())
                .eqIfPresent(IotRyDailyReportDO::getAuditStatus, reqVO.getAuditStatus())
                .betweenIfPresent(IotRyDailyReportDO::getCreateTime, reqVO.getCreateTime())
                .orderByDesc(IotRyDailyReportDO::getCreateTime)
                .orderByAsc(IotRyDailyReportDO::getId);
        return wrapper;
    }

    /**
     * 根据条件查询 瑞鹰 日报记录
     *
     * @param deptId     施工队伍 id
     * @param taskId     任务ID，可选参数，用于筛选任务ID匹配的记录
     * @param dateTime   当前时间
     * @return 返回符合条件的 瑞鹰 日报记录
     */
    default IotRyDailyReportDO selectExistReport(Long deptId, Long taskId, LocalDateTime dateTime) {
        String dateStr = ObjUtil.isNotEmpty(dateTime) ? dateTime.format(DateTimeFormatter.ofPattern("yyyy-MM-dd")) : StrUtil.EMPTY;
        // 使用LambdaQueryWrapperX构建查询条件，根据传入的参数动态添加查询条件
        return selectOne(new LambdaQueryWrapperX<IotRyDailyReportDO>()
                .eqIfPresent(IotRyDailyReportDO::getDeptId, deptId)
                .eqIfPresent(IotRyDailyReportDO::getTaskId, taskId)
                .apply(StrUtil.isNotBlank(dateStr), "DATE(create_time) = {0}", dateStr)
                .last("limit 1"));
    }

    /**
     * 查询指定日期前的最新日报记录
     *
     * @param deptId   施工队伍id
     * @param taskId   任务ID
     * @param dateTime 截止日期
     * @return 最新日报记录
     */
    default IotRyDailyReportDO selectLatestReportBeforeDate(Long deptId, Long taskId, LocalDateTime dateTime) {
        String dateStr = dateTime != null ? dateTime.format(DateTimeFormatter.ofPattern("yyyy-MM-dd")) : "";
        return selectOne(new LambdaQueryWrapperX<IotRyDailyReportDO>()
                .eqIfPresent(IotRyDailyReportDO::getDeptId, deptId)
                .eqIfPresent(IotRyDailyReportDO::getTaskId, taskId)
                .apply(StrUtil.isNotBlank(dateStr), "DATE(create_time) < {0}", dateStr)
                .orderByDesc(IotRyDailyReportDO::getCreateTime)
                .last("limit 1"));
    }

    /**
     * 查询瑞鹰日报实际进度
     *
     * @param reqVO
     * @return 瑞鹰日报实际进度
     */
    List<IotRyDailyReportDO> selectListGrouped(@Param("reqVO") IotRyDailyReportPageReqVO reqVO);

    /**
     * 查询每个施工队伍的 上井次完井时间
     * @param reqVO
     * @return
     */
    List<IotRyDailyReportDO> latestWellDoneTimes(@Param("reqVO") IotRyDailyReportPageReqVO reqVO);

    /**
     * 查询指定部门、指定时间段 填写的日报记录的 ’月进尺数据‘(逻辑细则：reportDate 所在的月份与数据表的字段 construction_start_date
     * 所在的月份相匹配 且 create_time < reportDate 的记录的 ’daily_footage‘ 字段值累加计算得出
     * @param deptId
     * @param reportDate
     * @return
     */
    default BigDecimal monthlyFootages(Long deptId, LocalDateTime reportDate) {
        if (reportDate == null) {
            return BigDecimal.ZERO;
        }
        // 获取 reportDate 的前一天日期
        LocalDateTime previousDay = reportDate.minusDays(1);
        // int year = previousDay.getYear();
        // int month = previousDay.getMonthValue();
        int year = reportDate.getYear();
        int month = reportDate.getMonthValue();

        List<IotRyDailyReportDO> list = selectList(new LambdaQueryWrapperX<IotRyDailyReportDO>()
                .eq(ObjUtil.isNotNull(deptId), IotRyDailyReportDO::getDeptId, deptId)
                .lt(IotRyDailyReportDO::getCreateTime, reportDate)
                .apply("YEAR(create_time) = {0}", year)
                .apply("MONTH(create_time) = {0}", month));

        return list.stream()
                .map(IotRyDailyReportDO::getDailyFootage)
                .filter(Objects::nonNull)
                .reduce(BigDecimal.ZERO, BigDecimal::add);
    }

    /**
     * 查询指定部门、工单生成日期 前一天所在月份的最早的记录天 井深
     * @param deptId
     * @param reportDate
     * @return
     */
    default BigDecimal monthStartFootage(Long deptId, LocalDateTime reportDate) {
        if (reportDate == null) {
            return BigDecimal.ZERO;
        }
        // 获取 reportDate 的前一天日期 查询前一天所在月份的井深
        LocalDateTime previousDay = reportDate.minusDays(1);
        int year = previousDay.getYear();
        int month = previousDay.getMonthValue();

        IotRyDailyReportDO report = selectOne(new LambdaQueryWrapperX<IotRyDailyReportDO>()
                .eqIfPresent(IotRyDailyReportDO::getDeptId, deptId)
                .apply("YEAR(construction_start_date) = {0}", year)
                .apply("MONTH(construction_start_date) = {0}", month)
                .orderByAsc(IotRyDailyReportDO::getCreateTime)
                .last("limit 1"));

        return ObjUtil.isEmpty(report) ? BigDecimal.ZERO : report.getCurrentDepth();
    }

    /**
     * 查询每个施工队伍的 历史 年进尺
     * @param deptId 部门ID
     * @param reportDate 报告日期
     * @return 年进尺总和
     */
    default BigDecimal annualFootages(Long deptId, LocalDateTime reportDate) {
        if (reportDate == null) {
            return BigDecimal.ZERO;
        }
        // 获取 reportDate 的前一天日期
        LocalDateTime previousDay = reportDate.minusDays(1);
        // int year = previousDay.getYear();
        int year = reportDate.getYear();

        List<IotRyDailyReportDO> list = selectList(new LambdaQueryWrapperX<IotRyDailyReportDO>()
                .eq(ObjUtil.isNotNull(deptId), IotRyDailyReportDO::getDeptId, deptId)
                .lt(IotRyDailyReportDO::getCreateTime, reportDate)
                .apply("YEAR(create_time) = {0}", year));

        return list.stream()
                .map(IotRyDailyReportDO::getDailyFootage)
                .filter(Objects::nonNull)
                .reduce(BigDecimal.ZERO, BigDecimal::add);
    }

    /**
     * 查询指定部门、工单生成日期 前一天所在年份的最早记录天 井深
     * @param deptId
     * @param reportDate
     * @return
     */
    default BigDecimal yearStartFootage(Long deptId, LocalDateTime reportDate) {
        if (reportDate == null) {
            return BigDecimal.ZERO;
        }
        // 获取 reportDate 的前一天日期 查询前一天所在年份每一条记录天的井深
        LocalDateTime previousDay = reportDate.minusDays(1);
        int year = previousDay.getYear();
        int month = previousDay.getMonthValue();

        IotRyDailyReportDO report = selectOne(new LambdaQueryWrapperX<IotRyDailyReportDO>()
                .eqIfPresent(IotRyDailyReportDO::getDeptId, deptId)
                .apply("YEAR(construction_start_date) = {0}", year)
                .orderByAsc(IotRyDailyReportDO::getCreateTime)
                .last("limit 1"));

        return ObjUtil.isEmpty(report) ? BigDecimal.ZERO : report.getCurrentDepth();
    }

    /**
     * 按部门统计 钻井 任务数量 完工任务数量
     * @return 部门任务统计列表
     */
    @Select("SELECT " +
            "dept_id as deptId, " +
            "COUNT(DISTINCT CASE WHEN task_id IS NOT NULL THEN task_id END) as totalTaskCount, " +
            "COUNT(DISTINCT CASE WHEN rig_status = 'wg' AND task_id IS NOT NULL THEN task_id END) as completedTaskCount " +
            "FROM rq_iot_ry_daily_report " +
            "WHERE deleted = 0 " +
            "AND (project_classification = 1 OR project_classification = '') " +
            "GROUP BY dept_id")
    List<IotRyDailyReportTaskCountVO> countTasksByDept();

    /**
     * 按部门统计 修井 任务数量 完工任务数量
     * @return 部门任务统计列表
     */
    @Select({
            "<script>",
            "SELECT ",
            "dept_id as deptId, ",
            "COUNT(DISTINCT CASE WHEN task_id IS NOT NULL THEN task_id END) as totalTaskCount, ",
            "COUNT(DISTINCT CASE WHEN repair_status = 'wg' AND task_id IS NOT NULL THEN task_id END) as completedTaskCount ",
            "FROM rq_iot_ry_daily_report ",
            "WHERE deleted = 0 ",
            "AND project_classification = 2 ",
            "<if test='reqVO.deptIds != null and !reqVO.deptIds.isEmpty()'>",
            "AND dept_id IN ",
            "<foreach collection='reqVO.deptIds' item='deptId' open='(' separator=',' close=')'>",
            "#{deptId}",
            "</foreach>",
            "</if>",
            "<if test='reqVO.createTime != null and reqVO.createTime[0] != null'>",
            "AND create_time &gt;= #{reqVO.createTime[0]} ",
            "</if>",
            "<if test='reqVO.createTime != null and reqVO.createTime[1] != null'>",
            "AND create_time &lt;= #{reqVO.createTime[1]} ",
            "</if>",
            "GROUP BY dept_id",
            "</script>"
    })
    List<IotRyDailyReportTaskCountVO> countRepairTasksByDept(@Param("reqVO") IotRyDailyReportPageReqVO reqVO);

    /**
     * 按部门统计 修井 任务数量 完工任务数量 当前日期所属的月 年
     * @return 部门任务统计列表
     */
    @Select("SELECT " +
            "dept_id as deptId, " +
            "COUNT(DISTINCT CASE WHEN task_id IS NOT NULL AND YEAR(create_time) = YEAR(CURDATE()) AND MONTH(create_time) = MONTH(CURDATE()) THEN task_id END) as monthTotalTaskCount," +
            "COUNT(DISTINCT CASE WHEN repair_status = 'wg' AND task_id IS NOT NULL AND YEAR(create_time) = YEAR(CURDATE()) AND MONTH(create_time) = MONTH(CURDATE()) THEN task_id END) as monthCompletedTaskCount," +
            "COUNT(DISTINCT CASE WHEN task_id IS NOT NULL AND YEAR(create_time) = YEAR(CURDATE()) THEN task_id END) as yearTotalTaskCount," +
            "COUNT(DISTINCT CASE WHEN repair_status = 'wg' AND task_id IS NOT NULL AND YEAR(create_time) = YEAR(CURDATE()) THEN task_id END) as yearCompletedTaskCount " +
            "FROM rq_iot_ry_daily_report " +
            "WHERE deleted = 0 " +
            "AND project_classification = 2 " +
            "GROUP BY dept_id")
    List<IotRyDailyReportTaskCountVO> countDateRepairTasksByDept();

    /**
     * 按部门统计 钻井 任务数量 完工任务数量 当前日期所属的月 年
     * @return 部门任务统计列表
     */
    @Select("SELECT " +
            "dept_id as deptId, " +
            "COUNT(DISTINCT CASE WHEN task_id IS NOT NULL AND YEAR(create_time) = YEAR(CURDATE()) AND MONTH(create_time) = MONTH(CURDATE()) THEN task_id END) as monthTotalTaskCount," +
            "COUNT(DISTINCT CASE WHEN rig_status = 'wg' AND task_id IS NOT NULL AND YEAR(create_time) = YEAR(CURDATE()) AND MONTH(create_time) = MONTH(CURDATE()) THEN task_id END) as monthCompletedTaskCount," +
            "COUNT(DISTINCT CASE WHEN task_id IS NOT NULL AND YEAR(create_time) = YEAR(CURDATE()) THEN task_id END) as yearTotalTaskCount," +
            "COUNT(DISTINCT CASE WHEN rig_status = 'wg' AND task_id IS NOT NULL AND YEAR(create_time) = YEAR(CURDATE()) THEN task_id END) as yearCompletedTaskCount " +
            "FROM rq_iot_ry_daily_report " +
            "WHERE deleted = 0 " +
            "AND (project_classification = 1 OR project_classification = '') " +
            "GROUP BY dept_id")
    List<IotRyDailyReportTaskCountVO> countDateRigTasksByDept();

    /**
     * 统计钻井 日进尺 月累计进尺 年累计进尺
     * @return
     */
    @Select("SELECT " +
            "dept_id as deptId, " +
            "SUM(IF(DATE(create_time) = CURDATE(), daily_footage, 0)) as dailyFootage," +
            "SUM(IF(YEAR(create_time) = YEAR(CURDATE()) AND MONTH(create_time) = MONTH(CURDATE()), daily_footage, 0)) as monthlyFootage," +
            "SUM(IF(YEAR(create_time) = YEAR(CURDATE()), daily_footage, 0)) as annualFootage " +
            "FROM rq_iot_ry_daily_report " +
            "WHERE deleted = 0 " +
            "AND (project_classification = 1 OR project_classification = '')  " +
            "GROUP BY dept_id")
    List<IotRyDailyReportTaskCountVO> countDateDrillTasksByDept();

    /**
     * 按部门/任务 统计 钻井 完工任务数量 当前日期所属的 日 月 年
     * @return 部门 任务 统计列表
     */
    @Select("SELECT " +
            "dept_id as deptId, " +
            "COUNT(DISTINCT CASE WHEN rig_status = 'wg' AND task_id IS NOT NULL AND DATE(create_time) = CURDATE() THEN task_id END) as completedTaskCount," +
            "COUNT(DISTINCT CASE WHEN rig_status = 'wg' AND task_id IS NOT NULL AND YEAR(create_time) = YEAR(CURDATE()) AND MONTH(create_time) = MONTH(CURDATE()) THEN task_id END) as monthCompletedTaskCount," +
            "COUNT(DISTINCT CASE WHEN rig_status = 'wg' AND task_id IS NOT NULL AND YEAR(create_time) = YEAR(CURDATE()) THEN task_id END) as yearCompletedTaskCount " +
            "FROM rq_iot_ry_daily_report " +
            "WHERE deleted = 0 " +
            "AND (project_classification = 1 OR project_classification = '') " +
            "GROUP BY dept_id")
    List<IotRyDailyReportTaskCountVO> countDateRigTasksByDepartment();

    /**
     * 根据 井号 查询 瑞鹰日报 按照队伍分组 小计
     * @param page
     * @param reqVO
     * @param projectIds
     * @return
     */
    IPage<IotRyDailyReportDO> ryWellNameDailyReports(IPage<IotRyDailyReportDO> page, @Param("reqVO") IotRyDailyReportPageReqVO reqVO,
                                                     @Param("taskIds") Collection<Long> taskIds,
                                                     @Param("projectIds") Collection<Long> projectIds, @Param("deptIds") Collection<Long> deptIds);

    /**
     * 根据 井号 查询 瑞鹰日报 按照队伍分组 小计 查询小组内最后1条记录id
     * @param page
     * @param reqVO
     * @param projectIds
     * @return
     */
    @TenantIgnore
    List<IotRyDailyReportDO> ryWellNameDailyReportsGroupIds(IPage<IotRyDailyReportDO> page, @Param("reqVO") IotRyDailyReportPageReqVO reqVO,
                                                            @Param("taskIds") Collection<Long> taskIds,
                                                            @Param("projectIds") Collection<Long> projectIds, @Param("deptIds") Collection<Long> deptIds);

    /**
     * 根据 队伍 查询 瑞鹰日报 按照任务井分组 小计
     * @param page
     * @param reqVO
     * @param projectIds
     * @return
     */
    IPage<IotRyDailyReportDO> ryDeptDailyReports(IPage<IotRyDailyReportDO> page, @Param("reqVO") IotRyDailyReportPageReqVO reqVO,
                                                 @Param("taskIds") Collection<Long> taskIds,
                                                 @Param("projectIds") Collection<Long> projectIds, @Param("deptIds") Collection<Long> deptIds);

    /**
     * 以队伍为维度 查询 井号 分组后的 瑞鹰日报 按照任务井分组 小计 查询小组内最后1条记录id
     * @param page
     * @param reqVO
     * @param projectIds
     * @return
     */
    List<IotRyDailyReportDO> ryDeptDailyReportsGroupIds(IPage<IotRyDailyReportDO> page, @Param("reqVO") IotRyDailyReportPageReqVO reqVO,
                                                        @Param("taskIds") Collection<Long> taskIds,
                                                        @Param("projectIds") Collection<Long> projectIds, @Param("deptIds") Collection<Long> deptIds);

    /**
     * 瑞鹰日报状态统计
     * @param reqVO
     * @return
     */
    List<AllOrderResp> selectStatusNumber(@Param("reqVO") IotMaintainPageReqVO reqVO);
}