# DbReportController.java

    package cloud.wconnect.workperformance.controller.database;

    import cloud.wconnect.commonlib.annotation.ApiId;
    import cloud.wconnect.commonlib.component.SessionContext;
    import cloud.wconnect.commonlib.cons.*;
    import cloud.wconnect.commonlib.exception.BadRequestException;
    import cloud.wconnect.commonlib.pojo.dto.ListPagedDTO;
    import cloud.wconnect.commonlib.pojo.dto.PropertyDTO;
    import cloud.wconnect.commonlib.pojo.dto.result.ResultDTO;
    import cloud.wconnect.commonlib.redis.PropertyI18nRedisService;
    import cloud.wconnect.commonlib.util.I18nMessageUtils;
    import cloud.wconnect.workperformance.cons.S3BucketFunctionCons;
    import cloud.wconnect.workperformance.cons.database.DbCons;
    import cloud.wconnect.workperformance.entity.database.DbReportImportLog;
    import cloud.wconnect.workperformance.pojo.dto.database.report.DbReportImportLogDTO;
    import cloud.wconnect.workperformance.pojo.dto.database.report.DbImportReportDTO;
    import cloud.wconnect.workperformance.pojo.dto.database.report.DbResolveReportExceptionDTO;
    import cloud.wconnect.workperformance.pojo.query.database.DbReportImportLogQuery;
    import cloud.wconnect.workperformance.service.AmazonS3Service;
    import cloud.wconnect.workperformance.service.database.IDbAutoResolveReportService;
    import cloud.wconnect.workperformance.service.database.IDbManualHandleReportService;
    import cloud.wconnect.workperformance.service.database.IDbReportImportLogService;
    import com.google.common.collect.Lists;
    import jakarta.annotation.Resource;
    import jakarta.validation.Valid;
    import org.apache.commons.lang3.StringUtils;
    import org.springframework.context.ApplicationContext;
    import org.springframework.web.bind.annotation.*;
    import org.springframework.web.multipart.MultipartFile;

    import java.text.MessageFormat;
    import java.util.*;

    /**
     * <p>
     * Database 前端控制器
     * </p>
     *
     * @author zc
     * @since 2025-12-02
     */
    @RestController
    @RequestMapping("/database/report")
    public class DbReportController {

        @Resource
        private IDbReportImportLogService importLogService;
        @Resource
        private PropertyI18nRedisService propertyI18nRedisService;
        @Resource
        private SessionContext sessionContext;
        @Resource
        private ApplicationContext applicationContext;
        @Resource
        private I18nMessageUtils i18nMessageUtils;
        @Resource
        private AmazonS3Service amazonS3Service;

        /**
         * 导入报告
         *
         * @param property  资产标识
         * @param reportDTO Import Report DTO
         * @return empty map
         * @author zc
         * @date 2025/12/02
         */
        @ApiId(1656)
        @PostMapping
        public ResultDTO<Void> importReport(@RequestParam String property, @Valid DbImportReportDTO reportDTO) {
            int propertyId = sessionContext.getPropertyId(property);
            PropertyDTO propertyDTO = propertyI18nRedisService.get(propertyId);

            // 校验数据集成参数
            checkDataIntegrationParams(propertyDTO.getPmsType(), reportDTO.getSource(), reportDTO.getReportType());

            int loginUserId = sessionContext.getLoginUserId();

            long businessDate = reportDTO.getBusinessDate();
            String source = reportDTO.getSource();
            int reportType = reportDTO.getReportType();
            MultipartFile file = reportDTO.getFile();
            List<Long> dateRange = Lists.newArrayList(reportDTO.getStartDate(), reportDTO.getEndDate());

            Collection<IDbManualHandleReportService> services = applicationContext.getBeansOfType(IDbManualHandleReportService.class).values();
            for (IDbManualHandleReportService service : services) {
                if (service.supports(reportType)) {
                    // 校验日期参数
                    service.checkDate(propertyDTO, source, reportDTO);
                    // 校验文件
                    service.checkFile(propertyDTO, source, file);
                    // 创建处理中的导入记录
                    DbReportImportLog importLog = importLogService.saveInProgress(propertyDTO, reportType, businessDate, dateRange, loginUserId);
                    // 处理数据
                    service.handleData(propertyDTO, file, importLog, loginUserId, source);
                    break;
                }
            }
            return ResultDTO.success();
        }

        /**
         * 获取报告导入记录
         *
         * @param property 资产标识
         * @param query    查询条件
         * @return PmsDbImportLogDTO 集合
         * @author zc
         * @date 2025/12/02
         */
        @ApiId(1657)
        @GetMapping("/import-log")
        public ResultDTO<ListPagedDTO<DbReportImportLogDTO>> list(@RequestParam String property, @Valid DbReportImportLogQuery query) {
            int propertyId = sessionContext.getPropertyId(property);
            PropertyDTO propertyDTO = propertyI18nRedisService.get(propertyId);
            // 校验报告类型参数
            checkReportTypeParams(propertyDTO.getPmsType(), query.getReportType());

            return ResultDTO.success(importLogService.list(propertyDTO, query));
        }

        /**
         * 解决导入异常记录
         *
         * @param property   资产标识
         * @param id         异常记录 id
         * @param resolveDTO 解决异常DTO
         * @return empty map
         * @author zc
         * @date 2025/12/02
         */
        @ApiId(1658)
        @PutMapping("/import-log/{id:\\d+}/resolve")
        public ResultDTO<Void> resolve(@RequestParam String property, @PathVariable("id") long id,
                                       @Valid DbResolveReportExceptionDTO resolveDTO) {
            int propertyId = sessionContext.getPropertyId(property);
            PropertyDTO propertyDTO = propertyI18nRedisService.get(propertyId);
            // 校验是否存在
            DbReportImportLog importLog = importLogService.checkExist(id);
            // 校验归属
            importLogService.checkBelong(propertyId, importLog);

            if (DbResolveReportExceptionDTO.IGNORE == resolveDTO.getType()) {
                // 校验是否是失败、缺失记录
                checkImportResultIsException(importLog.getImportResult());
                importLogService.ignore(importLog, sessionContext.getLoginUserId());
            } else if (DbResolveReportExceptionDTO.MANUAL_RESOLVE == resolveDTO.getType()) {
                manualResolve(propertyDTO, importLog, resolveDTO);
            } else {
                autoResolve(propertyDTO, importLog);
            }
            return ResultDTO.success();
        }

        /**
         * 自动解决报告异常
         *
         * @param propertyDTO 资产
         * @param importLog   导入记录
         * @author zc
         * @date 2025/12/2
         */
        private void autoResolve(PropertyDTO propertyDTO, DbReportImportLog importLog) {
            // 只能自动解决缺失状态的记录
            if (importLog.getImportResult() != ReportImportResultCons.IMPORT_RESULT_MISSED) {
                throw new BadRequestException(CommonErrorI18nConstant.DATA_INTEGRATION_ONLY_HANDLE_MISSED,
                        BaseErrorCodeEnum.DATA_VALIDATION_ERROR.getCode(),
                        "Only report import records with missing status can be processed");
            }

            if (StringUtils.isBlank(importLog.getUrl())) {
                throw new BadRequestException(CommonErrorI18nConstant.CANNOT_EMPTY,
                        i18nMessageUtils.getErrorParamMapNeedTranslate(CommonFieldI18nConstant.FILE),
                        BaseErrorCodeEnum.DATA_VALIDATION_ERROR.getCode(),
                        "The s3 file cannot empty.");
            }

            boolean fileExists = amazonS3Service.isFileExists(S3BucketFunctionCons.DATABASE_IMPORT_RECORD, importLog.getUrl());
            if (!fileExists) {
                throw new BadRequestException(CommonErrorI18nConstant.DATA_INTEGRATION_FILE_EXPIRED,
                        BaseErrorCodeEnum.DATA_VALIDATION_ERROR.getCode(),
                        "The file has expired and cannot be automatically resolved.");
            }
            int loginUserId = sessionContext.getLoginUserId();

            Collection<IDbAutoResolveReportService> services = applicationContext.getBeansOfType(IDbAutoResolveReportService.class).values();
            for (IDbAutoResolveReportService service : services) {
                if (service.supports(importLog.getReportType())) {
                    service.autoResolve(propertyDTO, importLog, loginUserId, propertyDTO.getPmsType());
                    break;
                }
            }
        }

        /**
         * 手动解决报告异常
         *
         * @param propertyDTO 资产
         * @param importLog   导入记录
         * @param resolveDTO  解决异常DTO
         * @author zc
         * @date 2025/12/2
         */
        private void manualResolve(PropertyDTO propertyDTO, DbReportImportLog importLog, DbResolveReportExceptionDTO resolveDTO) {
            // 校验是否是失败、缺失记录
            checkImportResultIsException(importLog.getImportResult());

            MultipartFile file = resolveDTO.getFile();
            // 校验文件不能为空
            if (Objects.isNull(file)) {
                throw new BadRequestException(CommonErrorI18nConstant.CANNOT_EMPTY,
                        i18nMessageUtils.getErrorParamMapNeedTranslate(CommonFieldI18nConstant.FILE),
                        BaseErrorCodeEnum.DATA_VALIDATION_ERROR.getCode(),
                        "The file cannot empty.");
            }
            String source = resolveDTO.getSource();
            if (StringUtils.isBlank(source)) {
                throw new BadRequestException(CommonErrorI18nConstant.CANNOT_EMPTY,
                        i18nMessageUtils.getErrorParamMapNeedTranslate(CommonFieldI18nConstant.DATA_INTEGRATION_SOURCE),
                        BaseErrorCodeEnum.DATA_VALIDATION_ERROR.getCode(),
                        "The source cannot empty.");
            }
            // 校验数据集成参数
            checkDataIntegrationParams(propertyDTO.getPmsType(), source, importLog.getReportType());

            int loginUserId = sessionContext.getLoginUserId();

            Collection<IDbManualHandleReportService> services =
                    applicationContext.getBeansOfType(IDbManualHandleReportService.class).values();
            for (IDbManualHandleReportService service : services) {
                if (service.supports(importLog.getReportType())) {
                    // 校验文件
                    service.checkFile(propertyDTO, source, file);
                    // 更新记录为修复中
                    importLogService.updateById(new DbReportImportLog().setId(importLog.getId())
                            .setImportResult(ReportImportResultCons.IMPORT_RESULT_REPAIRING));
                    // 处理数据
                    service.handleData(propertyDTO, file, importLog, loginUserId, source);
                    break;
                }
            }
        }

        /**
         * 校验是否是失败、缺失记录
         *
         * @param importResult 导入结果
         * @author zc
         * @date 2025/12/02
         */
        private void checkImportResultIsException(int importResult) {
            if (importResult != ReportImportResultCons.IMPORT_RESULT_FAIL
                    && importResult != ReportImportResultCons.IMPORT_RESULT_MISSED) {
                throw new BadRequestException(CommonErrorI18nConstant.DATA_INTEGRATION_ONLY_HANDLE_EXCEPTION,
                        BaseErrorCodeEnum.DATA_VALIDATION_ERROR.getCode(),
                        "Cannot operate status is not importResultFail or importResultMissed log");
            }
        }

        /**
         * 校验数据集成参数
         *
         * @param propertyPmsType 属性PMS类型
         * @param sourceSystem    来源系统
         * @param reportType      报告类型
         * @author zc
         * @date 2025/12/02
         */
        private void checkDataIntegrationParams(String propertyPmsType, String sourceSystem, int reportType) {
            List<String> effectSourceList = List.of(propertyPmsType, SystemPlatformEnum.OTHER.getDesc());
            if (!effectSourceList.contains(sourceSystem)) {
                throw new BadRequestException(CommonErrorI18nConstant.DATA_INTEGRATION_SOURCE_SYSTEM_NOT_SUPPORTED,
                        BaseErrorCodeEnum.DATA_VALIDATION_ERROR.getCode(),
                        MessageFormat.format("The currently selected source system is not supported, " +
                                "sourceSystem must be in {0}", effectSourceList));
            }
            // 校验报告类型参数
            checkReportTypeParams(propertyPmsType, reportType);
        }

        /**
         * 校验报告类型参数
         *
         * @param propertyPmsType 属性PMS类型
         * @param reportType      报告类型
         * @author zc
         * @date 2025/12/02
         */
        private void checkReportTypeParams(String propertyPmsType, int reportType) {
            List<Integer> effectReportTypeList;
            if (SystemPlatformEnum.OPERA.getDesc().equals(propertyPmsType)) {
                effectReportTypeList = DbCons.OPERA_PMS_TYPE_LIST;
            } else if (SystemPlatformEnum.SHI_JI.getDesc().equals(propertyPmsType)) {
                effectReportTypeList = DbCons.SHIJI_PMS_TYPE_LIST;
            } else {
                effectReportTypeList = DbCons.PEP_PMS_TYPE_LIST;
            }
            if (!new HashSet<>(effectReportTypeList).contains(reportType)) {
                throw new BadRequestException(CommonErrorI18nConstant.DATA_INTEGRATION_REPORT_TYPE_NOT_SUPPORTED,
                        BaseErrorCodeEnum.DATA_VALIDATION_ERROR.getCode(),
                        MessageFormat.format("The currently selected report type is not supported, " +
                                "reportType must be in {0}", effectReportTypeList));
            }
        }
    }