package com.hotwj.platform.reportStatistics.service.impl;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.StrUtil;
import com.hotwj.platform.reportStatistics.service.IReportDataProvider;
import com.hotwj.platform.reportStatistics.service.IVehicleFilePrintService;
import com.hotwj.platform.reportStatistics.service.ReportRenderService;
import com.hotwj.platform.resourceManagement.vehicleAnnualReview.domain.vo.HotVehicleAnnualReviewVo;
import com.hotwj.platform.resourceManagement.vehicleAnnualReview.service.IHotVehicleAnnualReviewService;
import com.hotwj.platform.resourceManagement.vehicleManagement.domain.vo.HotVehicleVo;
import com.hotwj.platform.resourceManagement.vehicleManagement.service.IHotVehicleService;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;

import java.util.Date;
import java.util.List;
import java.util.Map;

/**
 * 车辆档案打印
 *
 * @author shihongwei
 * @date 2026-01-02
 */
@Slf4j
@Service
@RequiredArgsConstructor
public class VehicleFilePrintServiceImpl implements IVehicleFilePrintService {

    private final IHotVehicleService hotVehicleService;
    private final IHotVehicleAnnualReviewService annualReviewService;
    private final ReportRenderService reportRenderService;

    // 使用 Map 注入所有 Provider，key 为 BeanName，需要确保 Provider 注册时指定了名称或使用别名
    // 或者更好的是：使用 List<IReportDataProvider> 注入，然后构建 Map
    // 这里我们假设已经有一个机制可以获取 Provider，类似于 DriverFilePrintServiceImpl
    private final Map<String, IReportDataProvider> providerMap;

    // 为了支持 Map<String, IReportDataProvider> 注入，我们需要确保 Spring 能正确注入
    // 如果 IReportDataProvider 实现类没有指定 Bean Name，默认是类名首字母小写
    // 我们可以注入 List，然后在 PostConstruct 中构建 Map，或者使用构造器注入 List
    // 让我们修改为注入 List 并构建 Map，这样更稳健

    private final List<IReportDataProvider> allProviders;
    private Map<String, IReportDataProvider> typeToProviderMap;

    @jakarta.annotation.PostConstruct
    public void init() {
        typeToProviderMap = new java.util.HashMap<>();
        for (IReportDataProvider provider : allProviders) {
            typeToProviderMap.put(provider.getReportType(), provider);
        }
    }

    @Override
    public byte[] generateBaseInfoPdf(List<Long> vehicleIds) throws Exception {
        return generatePdf(vehicleIds, TYPE_BASE_INFO);
    }

    @Override
    public byte[] generateLicensePdf(List<Long> vehicleIds) throws Exception {
        return generatePdf(vehicleIds, TYPE_LICENSE);
    }

    @Override
    public byte[] generateInspectionReportPdf(List<Long> vehicleIds, String inspectionStartDate, String inspectionEndDate, Integer printEmptyData) throws Exception {
        Long companyId = resolveCompanyId(vehicleIds);
        IReportDataProvider provider = typeToProviderMap.get(TYPE_INSPECTION_REPORT);

        var job = reportRenderService.createJob(typeToProviderMap::get)
                .withCompanyId(companyId)
                .useSeal(true);

        boolean allowEmpty = printEmptyData == null || printEmptyData == 1;
        Date startDate = null;
        Date endDate = null;
        if (StrUtil.isNotBlank(inspectionStartDate)) {
            startDate = DateUtil.beginOfDay(DateUtil.parse(inspectionStartDate, "yyyy-MM-dd"));
        }
        if (StrUtil.isNotBlank(inspectionEndDate)) {
            endDate = DateUtil.endOfDay(DateUtil.parse(inspectionEndDate, "yyyy-MM-dd"));
        }

        if (vehicleIds != null) {
            for (Long id : vehicleIds) {
                if (id == null) {
                    continue;
                }
                HotVehicleAnnualReviewVo review = null;
                if (!allowEmpty) {
                    if (startDate != null || endDate != null) {
                        review = annualReviewService.queryLatestByVehicleIdAndReviewDateRange(String.valueOf(id), startDate, endDate);
                    } else {
                        review = annualReviewService.queryLatestByVehicleId(String.valueOf(id));
                    }
                    if (review == null) {
                        continue;
                    }
                }
                Map<String, Object> params = new java.util.HashMap<>();
                params.put("vehicleId", id);
                params.put("inspectionStartDate", inspectionStartDate);
                params.put("inspectionEndDate", inspectionEndDate);
                if (review != null) {
                    params.put("review", review);
                }
                job.add(provider, params);
            }
        }

        if (!allowEmpty && job.getSegments().isEmpty()) {
            throw new RuntimeException("暂无检测报告可打印");
        }

        return job.render();
    }

    @Override
    public byte[] generateMaintenanceRecordPdf(List<Long> vehicleIds, String maintenanceStartDate, String maintenanceEndDate, Integer printEmptyData) throws Exception {
        Long companyId = resolveCompanyId(vehicleIds);
        IReportDataProvider provider = typeToProviderMap.get(TYPE_MAINTENANCE_RECORD);

        var job = reportRenderService.createJob(typeToProviderMap::get)
                .withCompanyId(companyId)
                .useSeal(true);

        boolean allowEmpty = printEmptyData == null || printEmptyData == 1;
        if (vehicleIds != null) {
            for (Long id : vehicleIds) {
                if (id == null) {
                    continue;
                }
                Map<String, Object> params = new java.util.HashMap<>();
                params.put("vehicleId", id);
                params.put("maintenanceStartDate", maintenanceStartDate);
                params.put("maintenanceEndDate", maintenanceEndDate);
                params.put("printEmptyData", printEmptyData);
                if (!allowEmpty) {
                    Map<String, Object> data = provider.prepareData(params);
                    if (data == null) {
                        continue;
                    }
                }
                job.add(provider, params);
            }
        }

        if (!allowEmpty && job.getSegments().isEmpty()) {
            throw new RuntimeException("暂无可打印记录");
        }

        return job.render();
    }

    @Override
    public byte[] generateRepairRecordPdf(List<Long> vehicleIds, String beginTime, String endTime, Integer printEmptyData) throws Exception {
        Long companyId = resolveCompanyId(vehicleIds);
        IReportDataProvider provider = typeToProviderMap.get(TYPE_REPAIR_RECORD);

        var job = reportRenderService.createJob(typeToProviderMap::get)
                .withCompanyId(companyId)
                .useSeal(true);

        boolean allowEmpty = printEmptyData == null || printEmptyData == 1;
        if (vehicleIds != null) {
            for (Long id : vehicleIds) {
                if (id == null) {
                    continue;
                }
                Map<String, Object> params = new java.util.HashMap<>();
                params.put("vehicleId", id);
                params.put("beginTime", beginTime);
                params.put("endTime", endTime);
                params.put("printEmptyData", printEmptyData);
                if (!allowEmpty) {
                    Map<String, Object> data = provider.prepareData(params);
                    if (data == null) {
                        continue;
                    }
                }
                job.add(provider, params);
            }
        }

        if (!allowEmpty && job.getSegments().isEmpty()) {
            throw new RuntimeException("暂无可打印记录");
        }

        return job.render();
    }

    @Override
    public byte[] generateTrafficAccidentRecordPdf(List<Long> vehicleIds, String beginTime, String endTime, Integer printEmptyData) throws Exception {
        Long companyId = resolveCompanyId(vehicleIds);
        IReportDataProvider provider = typeToProviderMap.get(TYPE_VEHICLE_ACCIDENT_RECORD);

        var job = reportRenderService.createJob(typeToProviderMap::get)
                .withCompanyId(companyId)
                .useSeal(true);

        boolean allowEmpty = printEmptyData == null || printEmptyData == 1;
        if (vehicleIds != null) {
            for (Long id : vehicleIds) {
                if (id == null) {
                    continue;
                }
                Map<String, Object> params = new java.util.HashMap<>();
                params.put("vehicleId", id);
                params.put("beginTime", beginTime);
                params.put("endTime", endTime);
                params.put("printEmptyData", printEmptyData);
                if (!allowEmpty) {
                    Map<String, Object> data = provider.prepareData(params);
                    if (data == null) {
                        continue;
                    }
                }
                job.add(provider, params);
            }
        }

        if (!allowEmpty && job.getSegments().isEmpty()) {
            throw new RuntimeException("暂无可打印记录");
        }

        return job.render();
    }

    @Override
    public byte[] generateClaimRecordPdf(List<Long> vehicleIds, String beginTime, String endTime, Integer printEmptyData) throws Exception {
        Long companyId = resolveCompanyId(vehicleIds);
        IReportDataProvider provider = typeToProviderMap.get(TYPE_CLAIM_RECORD);

        var job = reportRenderService.createJob(typeToProviderMap::get)
                .withCompanyId(companyId)
                .useSeal(true);

        boolean allowEmpty = printEmptyData == null || printEmptyData == 1;
        if (vehicleIds != null) {
            for (Long id : vehicleIds) {
                if (id == null) {
                    continue;
                }
                Map<String, Object> params = new java.util.HashMap<>();
                params.put("vehicleId", id);
                params.put("beginTime", beginTime);
                params.put("endTime", endTime);
                params.put("printEmptyData", printEmptyData);
                if (!allowEmpty) {
                    Map<String, Object> data = provider.prepareData(params);
                    if (data == null) {
                        continue;
                    }
                }
                job.add(provider, params);
            }
        }

        if (!allowEmpty && job.getSegments().isEmpty()) {
            throw new RuntimeException("暂无可打印记录");
        }

        return job.render();
    }

    @Override
    public byte[] generateMileageRecordPdf(List<Long> vehicleIds, String beginTime, String endTime, Integer printEmptyData) throws Exception {
        Long companyId = resolveCompanyId(vehicleIds);
        IReportDataProvider provider = typeToProviderMap.get(TYPE_MILEAGE_RECORD);

        var job = reportRenderService.createJob(typeToProviderMap::get)
                .withCompanyId(companyId)
                .useSeal(true);

        boolean allowEmpty = printEmptyData == null || printEmptyData == 1;
        if (vehicleIds != null) {
            for (Long id : vehicleIds) {
                if (id == null) {
                    continue;
                }
                Map<String, Object> params = new java.util.HashMap<>();
                params.put("vehicleId", id);
                params.put("beginTime", beginTime);
                params.put("endTime", endTime);
                params.put("printEmptyData", printEmptyData);
                if (!allowEmpty) {
                    Map<String, Object> data = provider.prepareData(params);
                    if (data == null) {
                        continue;
                    }
                }
                job.add(provider, params);
            }
        }

        if (!allowEmpty && job.getSegments().isEmpty()) {
            throw new RuntimeException("暂无可打印记录");
        }

        return job.render();
    }

    @Override
    public byte[] generateOneClickPrintPdf(List<Long> vehicleIds, List<String> types, Integer printEmptyData) throws Exception {
        Long companyId = resolveCompanyId(vehicleIds);
        boolean allowEmpty = printEmptyData == null || printEmptyData == 1;

        var job = reportRenderService.createJob(typeToProviderMap::get)
                .withCompanyId(companyId)
                .useSeal(true); // 一键打印默认不盖章，或根据需求调整

        for (Long id : vehicleIds) {
            // 这里可以添加封面，目前暂未实现 VehicleCoverProvider，如有需要可添加
            // job.addCover("VEHICLE_COVER", Map.of("vehicleId", id));

            for (String type : types) {
                // 兼容处理：如果是车辆打印中的 ACCIDENT_RECORD，应指代 VEHICLE_ACCIDENT_RECORD
                if ("ACCIDENT_RECORD".equals(type)) {
                    type = IVehicleFilePrintService.TYPE_VEHICLE_ACCIDENT_RECORD;
                }

                IReportDataProvider provider = typeToProviderMap.get(type);
                if (provider != null) {
                    Map<String, Object> params = new java.util.HashMap<>();
                    params.put("vehicleId", id);
                    params.put("printEmptyData", printEmptyData);
                    if (!allowEmpty && shouldCheckEmptyData(type)) {
                        Map<String, Object> data = provider.prepareData(params);
                        if (data == null) {
                            continue;
                        }
                    }
                    job.add(provider, params);
                }
            }
        }
        if (!allowEmpty && job.getSegments().isEmpty()) {
            throw new RuntimeException("暂无可打印记录");
        }
        return job.render();
    }

    private boolean shouldCheckEmptyData(String type) {
        return !TYPE_BASE_INFO.equals(type) && !TYPE_LICENSE.equals(type);
    }

    private byte[] generatePdf(List<Long> vehicleIds, String reportType) {
        Long companyId = resolveCompanyId(vehicleIds);
        IReportDataProvider provider = typeToProviderMap.get(reportType);

        return reportRenderService.createJob(typeToProviderMap::get)
                .withCompanyId(companyId)
                .addBatch(provider, convertToStringList(vehicleIds), "vehicleId")
                .useSeal(true)
                .render();
    }

    private byte[] generatePdfWithParams(List<Long> vehicleIds, String reportType, String inspectionStartDate, String inspectionEndDate, Integer printEmptyData) {
        Long companyId = resolveCompanyId(vehicleIds);
        IReportDataProvider provider = typeToProviderMap.get(reportType);

        var job = reportRenderService.createJob(typeToProviderMap::get)
                .withCompanyId(companyId)
                .useSeal(true);

        boolean allowEmpty = printEmptyData == null || printEmptyData == 1;
        if (vehicleIds != null) {
            for (Long id : vehicleIds) {
                if (id == null) {
                    continue;
                }
                Map<String, Object> params = new java.util.HashMap<>();
                params.put("vehicleId", id);
                params.put("inspectionStartDate", inspectionStartDate);
                params.put("inspectionEndDate", inspectionEndDate);
                params.put("printEmptyData", printEmptyData);
                if (!allowEmpty) {
                    Map<String, Object> data = provider.prepareData(params);
                    if (data == null) {
                        continue;
                    }
                }
                job.add(provider, params);
            }
        }

        if (!allowEmpty && job.getSegments().isEmpty()) {
            throw new RuntimeException("暂无可打印记录");
        }

        return job.render();
    }

    private Long resolveCompanyId(List<Long> vehicleIds) {
        if (CollUtil.isEmpty(vehicleIds)) {
            return null;
        }
        Long firstId = vehicleIds.get(0);
        HotVehicleVo vehicle = hotVehicleService.queryById(firstId);
        if (vehicle == null) {
            return null;
        }
        return vehicle.getCompanyId();
    }

    private List<String> convertToStringList(List<Long> list) {
        if (list == null) return null;
        return list.stream().map(String::valueOf).toList();
    }
}
