package com.yd.csf.api.service.impl;

import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.yd.auth.core.dto.AuthUserDto;
import com.yd.auth.core.utils.SecurityUtil;
import com.yd.common.constant.RedisConstants;
import com.yd.common.enums.CommonEnum;
import com.yd.common.enums.DictTypeEnum;
import com.yd.common.enums.ProjectEnum;
import com.yd.common.exception.BusinessException;
import com.yd.common.result.Result;
import com.yd.common.utils.*;
import com.yd.csf.api.service.ApiAppointmentFileService;
import com.yd.csf.api.service.ApiAppointmentService;
import com.yd.csf.feign.dto.appointment.*;
import com.yd.csf.feign.dto.appointmentfile.ApiAppointmentFileDto;
import com.yd.csf.feign.dto.excel.*;
import com.yd.csf.feign.request.appointmentfile.ApiAppointmentFileAddRequest;
import com.yd.csf.feign.request.appointmentfile.ApiAppointmentFileEditRequest;
import com.yd.csf.feign.request.appointmentfile.ApiAppointmentFilePageRequest;
import com.yd.csf.feign.request.appointmentfile.ApiAppointmentImportExcelRequest;
import com.yd.csf.feign.response.appointmentfile.ApiAppointmentExportExcelResponse;
import com.yd.csf.feign.response.appointmentfile.ApiAppointmentFilePageResponse;
import com.yd.csf.feign.response.appointmentfile.ApiAppointmentImportExcelResponse;
import com.yd.csf.service.dto.AdditionalDto;
import com.yd.csf.service.dto.BeneficiaryDto;
import com.yd.csf.feign.dto.appointmentfile.ItineraryDto;
import com.yd.csf.service.model.*;
import com.yd.csf.service.service.*;
import com.yd.insurance.base.feign.client.insurancecompany.ApiInsuranceCompanyFeignClient;
import com.yd.oss.feign.client.ApiExcelFeignClient;
import com.yd.oss.feign.client.ApiPdfFeignClient;
import com.yd.oss.feign.enums.TemplateTypeEnum;
import com.yd.oss.feign.request.ApiGeneratePdfRequest;
import com.yd.oss.feign.request.ApiOssExportAppointmentExcelRequest;
import com.yd.oss.feign.response.ApiGeneratePdfResponse;
import com.yd.oss.feign.response.ApiOssExcelParseResponse;
import com.yd.oss.feign.response.ApiOssExportAppointmentExcelResponse;
import com.yd.product.feign.client.productlaunch.ApiProductLaunchFeignClient;
import com.yd.product.feign.request.productlaunch.ApiProductLaunchPageRequest;
import com.yd.product.feign.response.productlaunch.ApiProductLaunchPageResponse;
import com.yd.user.feign.response.sysdict.GetDictItemListByDictTypeResponse;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;
import org.springframework.web.multipart.MultipartFile;
import java.util.*;
import java.util.stream.Collectors;

/**
 * 预约附件信息业务实现类
 */
@Slf4j
@Service
public class ApiAppointmentFileServiceImpl implements ApiAppointmentFileService {

    @Autowired
    private IAppointmentFileService iAppointmentFileService;

    @Autowired
    private IAppointmentService iAppointmentService;

    @Autowired
    private ApiAppointmentService apiAppointmentService;

    @Autowired
    private IProductPlanService iProductPlanService;

    @Autowired
    private IAdditionalService iAdditionalService;

    @Autowired
    private IBeneficiaryService iBeneficiaryService;

    @Autowired
    private IInsurantService iInsurantService;

    @Autowired
    private IPolicyholderService iPolicyholderService;

    @Autowired
    private ISecondHolderService iSecondHolderService;

    @Autowired
    private ApiPdfFeignClient apiPdfFeignClient;

    @Autowired
    private ApiExcelFeignClient apiExcelFeignClient;

    @Autowired
    private ApiProductLaunchFeignClient apiProductLaunchFeignClient;

    @Autowired
    private ApiInsuranceCompanyFeignClient apiInsuranceCompanyFeignClient;

    @Autowired
    private RedisUtil redisUtil;

    /**
     * 预约附件信息分页查询
     * @param request
     * @return
     */
    @Override
    public Result<IPage<ApiAppointmentFilePageResponse>> page(ApiAppointmentFilePageRequest request) {
        Page<ApiAppointmentFilePageResponse> page = new Page<>(request.getPageNo(), request.getPageSize());
        IPage<ApiAppointmentFilePageResponse> iPage = iAppointmentFileService.page(page, request);
        return Result.success(iPage);
    }

    /**
     * 根据预约业务id获取附件列表信息
     * @param appointmentBizId
     * @return
     */
    @Override
    public Result<List<ApiAppointmentFileDto>> list(String appointmentBizId) {
        List<ApiAppointmentFileDto> dtoList = new ArrayList<>();
        List<AppointmentFile> list = iAppointmentFileService.queryList(appointmentBizId);
        if (!CollectionUtils.isEmpty(list)) {
            dtoList = list.stream().map(dto -> {
                ApiAppointmentFileDto fileDto = new ApiAppointmentFileDto();
                BeanUtils.copyProperties(dto,fileDto);
                return fileDto;
            }).collect(Collectors.toList());
        }
        return Result.success(dtoList);
    }

    /**
     * 新增预约附件信息
     * @param request
     * @return
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public Result add(ApiAppointmentFileAddRequest request) {
        //获取Security上下文当前用户的登录信息
        AuthUserDto authUserDto = SecurityUtil.getCurrentLoginUser();
        AppointmentFile appointmentFile = new AppointmentFile();
        BeanUtils.copyProperties(request,appointmentFile);
        appointmentFile.setAppointmentFileBizId(RandomStringGenerator.generateBizId16(CommonEnum.UID_TYPE_APPOINTMENT_FILE.getCode()));
        appointmentFile.setCreatorName(authUserDto.getUsername());
        iAppointmentFileService.saveOrUpdate(appointmentFile);
        return Result.success();
    }

    /**
     * 编辑预约附件信息
     * @param request
     * @return
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public Result edit(ApiAppointmentFileEditRequest request) {
        Result<AppointmentFile> result = checkAppointmentFileIsExist(request.getAppointmentFileBizId());
        AppointmentFile appointmentFile = result.getData();
        appointmentFile.setFileName(request.getFileName());
        iAppointmentFileService.saveOrUpdate(appointmentFile);
        return Result.success();
    }

    /**
     * 删除预约附件
     * @param appointmentFileBizId
     * @return
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public Result del(String appointmentFileBizId) {
        Result<AppointmentFile> result = checkAppointmentFileIsExist(appointmentFileBizId);
        AppointmentFile appointmentFile = result.getData();
        iAppointmentFileService.removeById(appointmentFile.getId());
        return Result.success();
    }

    /**
     * 下载预约附件
     * @param appointmentFileBizId
     * @return
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public Result download(String appointmentFileBizId) {
        return null;
    }

    /**
     * 生成行程单PDF
     * @param appointmentBizId
     * @return
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public Result<String> itineraryPdf(String appointmentBizId) {
        String url = "";
        //查询redis缓存的字典列表信息
        List<GetDictItemListByDictTypeResponse> dictTypeResponses = redisUtil.getCacheObject(RedisConstants.DICT_LIST);
        //获取行程单的数据
        ItineraryDto itineraryDto = iAppointmentService.getItineraryDto(appointmentBizId);
        if (!Objects.isNull(itineraryDto)) {
            //会面地点
            itineraryDto.setMeetingPoint(GetDictItemListByDictTypeResponse.getItemLabel(dictTypeResponses,
                    DictTypeEnum.CSF_AP_MEETING_POINT.getItemValue(),itineraryDto.getMeetingPoint()));
        }
        ApiGeneratePdfRequest request = new ApiGeneratePdfRequest();
        request.setDataObject(itineraryDto);
        request.setObjectId(appointmentBizId);
        request.setTemplateType(TemplateTypeEnum.XCD.getItemValue());
        request.setProjectBizId(ProjectEnum.CSF_PC.getProjectBizId());
        if (StringUtils.isNotBlank(itineraryDto.getName()) &&
                StringUtils.isNotBlank(itineraryDto.getArrivalTime())) {
            //咨询人和集合日（签单日）都不为空，文件名 = 咨询人 + 集合日（20260103）
            request.setCustomFileName(itineraryDto.getName() + DateUtil.yyMMdd(itineraryDto.getArrivalTime()));
        }
        Result<ApiGeneratePdfResponse> result = apiPdfFeignClient.generatePDF(request);
        if (!Objects.isNull(result.getData())) {
            url = result.getData().getUrl();
        }
        return Result.success(url);
    }

    /**
     * 获取行程单详情
     * @param appointmentBizId
     * @return
     */
    @Override
    public Result<ItineraryDto> itineraryDetail(String appointmentBizId) {
        //获取行程单的数据
        ItineraryDto itineraryDto = iAppointmentService.getItineraryDto(appointmentBizId);
        return Result.success(itineraryDto);
    }

    /**
     * Excel导出-预约信息
     * @param appointmentBizId
     * @return
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public Result<ApiAppointmentExportExcelResponse> appointmentExportExcel(String appointmentBizId) {
        Map<String, Object> data = new HashMap<>();
        try {
            //查询redis缓存的字典列表信息
            List<GetDictItemListByDictTypeResponse> dictTypeResponses = redisUtil.getCacheObject(RedisConstants.DICT_LIST);
            //预约信息
            Result<Appointment> result = apiAppointmentService.checkAppointmentIsExist(appointmentBizId);
            Appointment appointment = result.getData();

            //Excel-预约主信息
            ApiExcelAppointmentMainDto mainDto = new ApiExcelAppointmentMainDto();
            BeanUtils.copyProperties(appointment,mainDto);
            mainDto = ApiExcelAppointmentMainDto.setApiExcelAppointmentMainDto(mainDto);
            //对象转成map.方便excel做占位符字段替换
            Map<String, Object> mainMap = BeanMapUtils.convertToMapSafely(mainDto);
            data.putAll(mainMap);

            //Excel-预约资料及计划内容信息
            ProductPlan productPlan = iProductPlanService.queryOne(appointmentBizId,"");
            if (!Objects.isNull(productPlan)) {
                ApiExcelAppointmentPlanDto planDto = new ApiExcelAppointmentPlanDto();
                BeanUtils.copyProperties(productPlan,planDto);
                planDto = ApiExcelAppointmentPlanDto.setApiExcelAppointmentPlanDto(planDto,dictTypeResponses);
                //对象转成map.方便excel做占位符字段替换
                Map<String, Object> planMap = BeanMapUtils.convertToMapSafely(planDto);
                data.putAll(planMap);

                //附加计划（附加险）
                List<Additional> additionalList = iAdditionalService.queryList(AdditionalDto.builder()
                        .planBizId(productPlan.getPlanBizId())
                        .build());
                if (!CollectionUtils.isEmpty(additionalList)) {
                    List<ApiExcelAdditionalDto> additionalDtoList = additionalList
                            .stream()
                            .map(dto -> {
                                ApiExcelAdditionalDto additionalDto = new ApiExcelAdditionalDto();
                                BeanUtils.copyProperties(dto,additionalDto);
                                return additionalDto;
                            }).collect(Collectors.toList());

                    additionalDtoList = ApiExcelAdditionalDto.setApiExcelAdditionalDtoList(additionalDtoList);
                    List<Map<String, Object>> mapList = BeanMapUtils.convertListToMapListSafelyWithEmpty(additionalDtoList);
                    data.put("additionalList", mapList);
                }
            }

            //受益人列表
            List<Beneficiary> beneficiaryList = iBeneficiaryService.queryList(BeneficiaryDto.builder()
                    .appointmentBizId(appointmentBizId)
                    .build());
            if (!CollectionUtils.isEmpty(beneficiaryList)) {
                List<ApiExcelBeneficiaryDto> apiExcelBeneficiaryDtoList = beneficiaryList
                        .stream()
                        .map(dto -> {
                            ApiExcelBeneficiaryDto beneficiaryDto = new ApiExcelBeneficiaryDto();
                            BeanUtils.copyProperties(dto,beneficiaryDto);
                            return beneficiaryDto;
                        }).collect(Collectors.toList());
                apiExcelBeneficiaryDtoList = ApiExcelBeneficiaryDto.setApiExcelBeneficiaryDtoList(apiExcelBeneficiaryDtoList,dictTypeResponses);
                List<Map<String, Object>> mapList1 = BeanMapUtils.convertListToMapListSafelyWithEmpty(apiExcelBeneficiaryDtoList);
                data.put("beneficiaryList", mapList1);
            }

            //Excel-客戶在港/澳停留時間信息
            ApiExcelHkStayDto stayDto = new ApiExcelHkStayDto();
            BeanUtils.copyProperties(appointment,stayDto);
            stayDto = ApiExcelHkStayDto.setApiExcelHkStayDto(stayDto,dictTypeResponses);
            Map<String, Object> stayMap = BeanMapUtils.convertToMapSafely(stayDto);
            data.putAll(stayMap);

            //受保人资料 (如與保單持有人為同一人無須填寫)
            Insurant insurant = iInsurantService.queryOne(appointmentBizId,"");
            if (!Objects.isNull(insurant)) {
                ApiExcelInsurantDto insurantDto = new ApiExcelInsurantDto();
                BeanUtils.copyProperties(insurant,insurantDto);
                insurantDto = ApiExcelInsurantDto.setApiExcelInsurantDto(insurantDto,dictTypeResponses);
                //对象转成map.方便excel做占位符字段替换
                Map<String, Object> insurantMap = BeanMapUtils.convertToMapSafely(insurantDto);
                data.putAll(insurantMap);
            }

            //保单持有人资料（投保人信息）
            Policyholder policyholder = iPolicyholderService.queryOne(appointmentBizId,"");
            if (!Objects.isNull(policyholder)) {
                ApiExcelPolicyholderDto policyholderDto = new ApiExcelPolicyholderDto();
                BeanUtils.copyProperties(policyholder,policyholderDto);
                policyholderDto = ApiExcelPolicyholderDto.setApiExcelPolicyholderDto(policyholderDto,dictTypeResponses);
                //对象转成map.方便excel做占位符字段替换
                Map<String, Object> policyholderMap = BeanMapUtils.convertToMapSafely(policyholderDto);
                data.putAll(policyholderMap);
            }

            //第二持有人资料
            SecondHolder secondHolder = iSecondHolderService.queryOne(appointmentBizId,"");
            if (!Objects.isNull(secondHolder)) {
                ApiExcelSecondHolderDto secondHolderDto = new ApiExcelSecondHolderDto();
                BeanUtils.copyProperties(secondHolder,secondHolderDto);
                secondHolderDto = ApiExcelSecondHolderDto.setApiExcelSecondHolderDto(secondHolderDto,dictTypeResponses);
                //对象转成map.方便excel做占位符字段替换
                Map<String, Object> secondHolderMap = BeanMapUtils.convertToMapSafely(secondHolderDto);
                data.putAll(secondHolderMap);
            }
            ApiOssExportAppointmentExcelRequest excelRequest = new ApiOssExportAppointmentExcelRequest();
            excelRequest.setAppointmentBizId(appointmentBizId);
            excelRequest.setData(data);
            excelRequest.setTemplateType(TemplateTypeEnum.YYD.getItemValue());
            excelRequest.setProjectBizId(ProjectEnum.CSF_PC.getProjectBizId());
            Result<ApiOssExportAppointmentExcelResponse> result1 = apiExcelFeignClient.exportAppointment(excelRequest);
            ApiOssExportAppointmentExcelResponse excelResponse = result1.getData();
            ApiAppointmentExportExcelResponse response = new ApiAppointmentExportExcelResponse();
            response.setUrl(excelResponse.getUrl());
            return Result.success(response);
        } catch (Exception e) {
            e.printStackTrace();
            throw new BusinessException("Excel导出-预约信息异常！");
        }

    }


    /**
     * Excel导入-解析Excel预约信息
     * @param file
     * @param request
     * @return
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public Result<ApiAppointmentImportExcelResponse> appointmentImportExcel(MultipartFile file,
                                                                            ApiAppointmentImportExcelRequest request) {

        ApiAppointmentImportExcelResponse response = new ApiAppointmentImportExcelResponse();
        String s = "com.yd.csf.feign.dto.excel.ApiExcelImportAppointmentDto,com.yd.csf.feign.dto.excel.ApiExcelImportHealthDto";
        //Feign调用-oss服务，通用-Excel解析（支持多sheet页解析）
        Result<ApiOssExcelParseResponse> result = apiExcelFeignClient.parse(file, s);
        if (Objects.isNull(result.getData()) ||
                (!Objects.isNull(result.getData()) && Objects.isNull(result.getData().getMap()))){
            throw new BusinessException("导入数据不能为空！");
        }
        //Excel解析出的信息
        Map<Integer, Object> data = (Map<Integer, Object>) result.getData().getMap();
        ObjectMapper objectMapper = new ObjectMapper();

        try {
            //查询redis缓存的字典列表信息
            List<GetDictItemListByDictTypeResponse> dictTypeResponses = redisUtil.getCacheObject(RedisConstants.DICT_LIST);
            // 获取第一个Sheet页的解析结果并转换为 DTO
            LinkedHashMap<String, Object> appointmentData = (LinkedHashMap<String, Object>) data.get(0);
            ApiExcelImportAppointmentDto appointmentDto = objectMapper.convertValue(appointmentData, ApiExcelImportAppointmentDto.class);

            //设置预约主体信息
            ApiAppointmentInfoDto apiAppointmentInfoDto = new ApiAppointmentInfoDto();
            apiAppointmentInfoDto = ApiExcelImportAppointmentDto.buildApiAppointmentInfoDto(appointmentDto,apiAppointmentInfoDto,dictTypeResponses);
            response.setApiAppointmentInfoDto(apiAppointmentInfoDto);

            //设置产品计划主信息
            //调用 convertExcelPlanName 获取产品ID映射
            List<ApiConvertExcelPlanNameDto> convertList = convertExcelPlanName(appointmentDto);
            ApiProductPlanInfoDto apiProductPlanInfoDto = new ApiProductPlanInfoDto();
            ApiProductPlanMainInfoDto apiProductPlanMainInfoDto = new ApiProductPlanMainInfoDto();
            apiProductPlanMainInfoDto = ApiExcelImportAppointmentDto.buildApiProductPlanMainInfoDto(appointmentDto,apiProductPlanMainInfoDto,dictTypeResponses);
            //设置产品附加计划（附加险列表）
            List<ApiProductPlanAdditionalInfoDto> apiProductPlanAdditionalInfoDtoList = ApiExcelImportAppointmentDto.buildApiProductPlanAdditionalInfoDto(appointmentDto.getAdditionalDtoList(),dictTypeResponses);
            settingProductId(apiProductPlanMainInfoDto,apiProductPlanAdditionalInfoDtoList,convertList);

            apiProductPlanInfoDto.setApiProductPlanMainInfoDto(apiProductPlanMainInfoDto);
            apiProductPlanInfoDto.setApiProductPlanAdditionalInfoDtoList(apiProductPlanAdditionalInfoDtoList);
            response.setApiProductPlanInfoDto(apiProductPlanInfoDto);

            //设置投保人信息
            ApiPolicyholderInfoDto apiPolicyholderInfoDto = new ApiPolicyholderInfoDto();
            apiPolicyholderInfoDto = ApiExcelImportAppointmentDto.buildApiPolicyholderInfoDto(appointmentDto,apiPolicyholderInfoDto,dictTypeResponses);
            response.setApiPolicyholderInfoDto(apiPolicyholderInfoDto);

            //设置受保人信息
            ApiInsurantInfoDto apiInsurantInfoDto = new ApiInsurantInfoDto();
            apiInsurantInfoDto = ApiExcelImportAppointmentDto.buildApiInsurantInfoDto(appointmentDto,apiInsurantInfoDto,dictTypeResponses);
            response.setApiInsurantInfoDto(apiInsurantInfoDto);

            //编辑更新第二持有人信息
            //查询第二持有人信息
            ApiSecondHolderInfoDto apiSecondHolderInfoDto = new ApiSecondHolderInfoDto();
            apiSecondHolderInfoDto = ApiExcelImportAppointmentDto.buildApiSecondHolderInfoDto(appointmentDto,apiSecondHolderInfoDto,dictTypeResponses);
            response.setApiSecondHolderInfoDto(apiSecondHolderInfoDto);

            //新增受益人列表
            List<ApiBeneficiaryInfoDto> apiBeneficiaryInfoDtoList = ApiExcelImportAppointmentDto.buildApiBeneficiaryInfoDtoList(appointmentDto.getBeneficiaryDtoList(),dictTypeResponses);
            ApiBeneficiaryInfoFzDto fzDto = new ApiBeneficiaryInfoFzDto();
            fzDto.setApiBeneficiaryInfoDtoList(apiBeneficiaryInfoDtoList);
            response.setApiBeneficiaryInfoFzDto(fzDto);

            return Result.success(response);

        } catch (Exception e) {
            log.error("Excel数据转换异常", e);
            throw new BusinessException("Excel数据格式错误，请检查模板是否正确");
        }
    }

    public void settingProductId(ApiProductPlanMainInfoDto apiProductPlanMainInfoDto,
                                 List<ApiProductPlanAdditionalInfoDto> apiProductPlanAdditionalInfoDtoList,
                                 List<ApiConvertExcelPlanNameDto> convertList) {
        if (!CollectionUtils.isEmpty(convertList)) {
            ApiConvertExcelPlanNameDto convertDto = convertList.get(0); // 只有一个元素

            // 2. 更新主计划信息中的 productLaunchBizId
            if (StringUtils.isNotBlank(convertDto.getMainPlanId())) {
                apiProductPlanMainInfoDto.setProductLaunchBizId(convertDto.getMainPlanId());
                // 也可以将产品名称设置为原始名称（或转换后的名称）
                apiProductPlanMainInfoDto.setProductLaunchMainName(convertDto.getMainPlanName());
            }

            // 3. 更新附加计划列表中的 productLaunchBizId（假设有附加险列表）
            if (!CollectionUtils.isEmpty(apiProductPlanAdditionalInfoDtoList)) {
                // 第一个附加险
                if (apiProductPlanAdditionalInfoDtoList.size() >= 1 && StringUtils.isNotBlank(convertDto.getAddPlanId1())) {
                    apiProductPlanAdditionalInfoDtoList.get(0).setProductLaunchBizId(convertDto.getAddPlanId1());
                    apiProductPlanAdditionalInfoDtoList.get(0).setProductLaunchName(convertDto.getAddPlanName1());
                }
                // 第二个附加险
                if (apiProductPlanAdditionalInfoDtoList.size() >= 2 && StringUtils.isNotBlank(convertDto.getAddPlanId2())) {
                    apiProductPlanAdditionalInfoDtoList.get(1).setProductLaunchBizId(convertDto.getAddPlanId2());
                    apiProductPlanAdditionalInfoDtoList.get(1).setProductLaunchName(convertDto.getAddPlanName2());
                }
            }
        }
    }

    /**
     * 远程调用feign-根据Excel解析的数据-转换产品计划名称和ID
     * @param appointmentDto
     * @return
     */
    public List<ApiConvertExcelPlanNameDto> convertExcelPlanName(ApiExcelImportAppointmentDto appointmentDto) {
        // 1. 收集所有需要查询的产品名称（去重）
        Set<String> queryNameSet = new HashSet<>();

        // 主计划名称
        if (StringUtils.isNotBlank(appointmentDto.getPlanProductName())) {
            queryNameSet.add(ChineseTextConverter.traditionalToSimplified(appointmentDto.getPlanProductName()));
            queryNameSet.add(ChineseTextConverter.simplifiedToTraditional(appointmentDto.getPlanProductName()));
        }

        // 附加计划名称
        if (!CollectionUtils.isEmpty(appointmentDto.getAdditionalDtoList())) {
            for (ApiExcelImportAdditionalDto additionalDto : appointmentDto.getAdditionalDtoList()) {
                if (StringUtils.isNotBlank(additionalDto.getAddProductName())) {
                    queryNameSet.add(ChineseTextConverter.traditionalToSimplified(additionalDto.getAddProductName()));
                    queryNameSet.add(ChineseTextConverter.simplifiedToTraditional(additionalDto.getAddProductName()));
                }
            }
        }

        // 如果没有需要查询的名称，直接返回空
        if (queryNameSet.isEmpty()) {
            return Collections.emptyList();
        }

        // 2. 调用 Feign 批量查询产品上架信息
        ApiProductLaunchPageRequest pageRequest = new ApiProductLaunchPageRequest();
        pageRequest.setTitleList(new ArrayList<>(queryNameSet));
        // 设置分页参数，尽可能大一些以获取全部数据
        pageRequest.setPageNo(1);
        pageRequest.setPageSize(1000);

        Result<IPage<ApiProductLaunchPageResponse>> result = apiProductLaunchFeignClient.page(pageRequest);
        if (result == null || result.getData() == null || CollectionUtils.isEmpty(result.getData().getRecords())) {
            log.warn("未找到匹配的产品计划，查询名称列表：{}", queryNameSet);
            return Collections.emptyList();
        }

        // 3. 建立标题 -> 产品ID的映射（注意：标题可能因繁简不同而重复，这里使用原始返回的标题作为key）
        Map<String, String> titleToIdMap = result.getData().getRecords().stream()
                .filter(record -> StringUtils.isNotBlank(record.getTitle()))
                .collect(Collectors.toMap(
                        ApiProductLaunchPageResponse::getTitle,
                        ApiProductLaunchPageResponse::getProductLaunchBizId,
                        (v1, v2) -> v1  // 如果标题重复，取第一个（实际不会重复）
                ));

        // 4. 构建返回的 DTO
        ApiConvertExcelPlanNameDto dto = new ApiConvertExcelPlanNameDto();

        // 处理主计划
        String mainPlanOriginal = appointmentDto.getPlanProductName();
        if (StringUtils.isNotBlank(mainPlanOriginal)) {
            dto.setMainPlanName(mainPlanOriginal);
            // 优先用原始名称精确匹配，否则尝试用转换后的名称匹配
            String mainId = titleToIdMap.get(mainPlanOriginal);
            if (mainId == null) {
                // 尝试繁体/简体转换后的名称
                mainId = titleToIdMap.get(ChineseTextConverter.traditionalToSimplified(mainPlanOriginal));
                if (mainId == null) {
                    mainId = titleToIdMap.get(ChineseTextConverter.simplifiedToTraditional(mainPlanOriginal));
                }
            }
            dto.setMainPlanId(mainId);
            // 设置查询时使用的名称列表（繁简体）
            dto.setMainPlanNameList(Arrays.asList(
                    ChineseTextConverter.traditionalToSimplified(mainPlanOriginal),
                    ChineseTextConverter.simplifiedToTraditional(mainPlanOriginal)
            ));
        }

        // 处理附加计划（最多支持两个，根据 DTO 定义）
        if (!CollectionUtils.isEmpty(appointmentDto.getAdditionalDtoList())) {
            int size = appointmentDto.getAdditionalDtoList().size();
            // 第一个附加计划
            if (size >= 1) {
                ApiExcelImportAdditionalDto add1 = appointmentDto.getAdditionalDtoList().get(0);
                String addName1 = add1.getAddProductName();
                dto.setAddPlanName1(addName1);
                // 查找ID
                String addId1 = titleToIdMap.get(addName1);
                if (addId1 == null) {
                    addId1 = titleToIdMap.get(ChineseTextConverter.traditionalToSimplified(addName1));
                    if (addId1 == null) {
                        addId1 = titleToIdMap.get(ChineseTextConverter.simplifiedToTraditional(addName1));
                    }
                }
                dto.setAddPlanId1(addId1);
                dto.setAddPlanName1List(Arrays.asList(
                        ChineseTextConverter.traditionalToSimplified(addName1),
                        ChineseTextConverter.simplifiedToTraditional(addName1)
                ));
            }
            // 第二个附加计划
            if (size >= 2) {
                ApiExcelImportAdditionalDto add2 = appointmentDto.getAdditionalDtoList().get(1);
                String addName2 = add2.getAddProductName();
                dto.setAddPlanName2(addName2);
                String addId2 = titleToIdMap.get(addName2);
                if (addId2 == null) {
                    addId2 = titleToIdMap.get(ChineseTextConverter.traditionalToSimplified(addName2));
                    if (addId2 == null) {
                        addId2 = titleToIdMap.get(ChineseTextConverter.simplifiedToTraditional(addName2));
                    }
                }
                dto.setAddPlanId2(addId2);
                dto.setAddPlanName2List(Arrays.asList(
                        ChineseTextConverter.traditionalToSimplified(addName2),
                        ChineseTextConverter.simplifiedToTraditional(addName2)
                ));
            }
            // 如果超过两个，可以打印日志提示，但根据 DTO 设计只取前两个
            if (size > 2) {
                log.warn("附加计划数量超过2个，只处理前两个，总数：{}", size);
            }
        }

        return Collections.singletonList(dto);
    }


    /**
     * 校验预约附件信息是否存在
     * @param appointmentFileBizId
     * @return
     */
    public Result<AppointmentFile> checkAppointmentFileIsExist(String appointmentFileBizId) {
        AppointmentFile appointmentFile = iAppointmentFileService.queryOne(appointmentFileBizId);
        if (Objects.isNull(appointmentFile)) {
            //数据不存在
            throw new BusinessException("预约附件信息不存在");
        }
        return Result.success(appointmentFile);
    }
}
