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.exception.BusinessException;
import com.yd.common.result.Result;
import com.yd.common.utils.BeanMapUtils;
import com.yd.common.utils.RandomStringGenerator;
import com.yd.common.utils.RedisUtil;
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.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.user.feign.response.sysdict.GetDictItemListByDictTypeResponse;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
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 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
    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
    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
    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
    public Result download(String appointmentFileBizId) {
        return null;
    }

    /**
     * 生成行程单PDF
     * @param appointmentBizId
     * @return
     */
    @Override
    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());
        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
    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());
            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导入-预约信息
     * @param file
     * @param request
     * @return
     */
    @Override
    public Result<ApiAppointmentImportExcelResponse> appointmentImportExcel(MultipartFile file,
                                                                            ApiAppointmentImportExcelRequest request) {
        //校验预约信息是否存在
        Result<Appointment> appointmentResult = apiAppointmentService.checkAppointmentIsExist(request.getAppointmentBizId());
        Appointment appointment = appointmentResult.getData();

        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);

            // 获取第二个Sheet页的解析结果并转换为 DTO
//            LinkedHashMap<String, Object> healthData = (LinkedHashMap<String, Object>) data.get(1);
//            ApiExcelImportHealthDto healthDto = objectMapper.convertValue(healthData, ApiExcelImportHealthDto.class);

            //编辑更新预约主体信息
            ApiAppointmentInfoDto apiAppointmentInfoDto = new ApiAppointmentInfoDto();
            BeanUtils.copyProperties(appointment,apiAppointmentInfoDto);
            apiAppointmentInfoDto = ApiExcelImportAppointmentDto.buildApiAppointmentInfoDto(appointmentDto,apiAppointmentInfoDto,dictTypeResponses);
            BeanUtils.copyProperties(apiAppointmentInfoDto,appointment);
            iAppointmentService.saveOrUpdate(appointment);

            //编辑更新产品计划主信息
            //查询产品计划主信息
            ProductPlan productPlan = iProductPlanService.queryOne(request.getAppointmentBizId(),"");
            ApiProductPlanMainInfoDto apiProductPlanMainInfoDto = new ApiProductPlanMainInfoDto();
            if (!Objects.isNull(productPlan)) {
                BeanUtils.copyProperties(productPlan,apiProductPlanMainInfoDto);
                apiProductPlanMainInfoDto = ApiExcelImportAppointmentDto.buildApiProductPlanMainInfoDto(appointmentDto,apiProductPlanMainInfoDto,dictTypeResponses);
                BeanUtils.copyProperties(apiProductPlanMainInfoDto,productPlan);
                iProductPlanService.saveOrUpdate(productPlan);
                //新增附加计划（附加险列表）
                List<ApiProductPlanAdditionalInfoDto> apiBeneficiaryInfoDtoList = ApiExcelImportAppointmentDto.buildApiProductPlanAdditionalInfoDto(appointmentDto.getAdditionalDtoList(),dictTypeResponses,productPlan.getPlanBizId());
                if (!CollectionUtils.isEmpty(apiBeneficiaryInfoDtoList)) {
                    List<Additional> saveList = apiBeneficiaryInfoDtoList.stream().map(dto -> {
                        Additional additional = new Additional();
                        BeanUtils.copyProperties(dto,additional);
                        return additional;
                    }).collect(Collectors.toList());
                    iAdditionalService.saveOrUpdateBatch(saveList);
                }
            }

            //编辑更新投保人信息
            //查询投保人信息
            Policyholder policyholder = iPolicyholderService.queryOne(request.getAppointmentBizId(),"");
            ApiPolicyholderInfoDto apiPolicyholderInfoDto = new ApiPolicyholderInfoDto();
            if (!Objects.isNull(policyholder)) {
                BeanUtils.copyProperties(policyholder,apiPolicyholderInfoDto);
                apiPolicyholderInfoDto = ApiExcelImportAppointmentDto.buildApiPolicyholderInfoDto(appointmentDto,apiPolicyholderInfoDto,dictTypeResponses);
                BeanUtils.copyProperties(apiPolicyholderInfoDto,policyholder);
                iPolicyholderService.saveOrUpdate(policyholder);
            }

            //编辑更新受保人信息
            //查询受保人信息
            Insurant insurant = iInsurantService.queryOne(request.getAppointmentBizId(),"");
            ApiInsurantInfoDto apiInsurantInfoDto = new ApiInsurantInfoDto();
            if (!Objects.isNull(insurant)) {
                BeanUtils.copyProperties(insurant,apiInsurantInfoDto);
                apiInsurantInfoDto = ApiExcelImportAppointmentDto.buildApiInsurantInfoDto(appointmentDto,apiInsurantInfoDto,dictTypeResponses);
                BeanUtils.copyProperties(apiInsurantInfoDto,insurant);
                iInsurantService.saveOrUpdate(insurant);
            }

            //编辑更新第二持有人信息
            //查询第二持有人信息
            SecondHolder secondHolder = iSecondHolderService.queryOne(request.getAppointmentBizId(),"");
            ApiSecondHolderInfoDto apiSecondHolderInfoDto = new ApiSecondHolderInfoDto();
            if (!Objects.isNull(secondHolder)) {
                BeanUtils.copyProperties(secondHolder,apiSecondHolderInfoDto);
                apiSecondHolderInfoDto = ApiExcelImportAppointmentDto.buildApiSecondHolderInfoDto(appointmentDto,apiSecondHolderInfoDto,dictTypeResponses);
                BeanUtils.copyProperties(apiSecondHolderInfoDto,secondHolder);
                iSecondHolderService.saveOrUpdate(secondHolder);
            }

            //新增受益人列表
            List<ApiBeneficiaryInfoDto> apiBeneficiaryInfoDtoList = ApiExcelImportAppointmentDto.buildApiBeneficiaryInfoDtoList(appointmentDto.getBeneficiaryDtoList(),dictTypeResponses,request.getAppointmentBizId());
            if (!CollectionUtils.isEmpty(apiBeneficiaryInfoDtoList)) {
                List<Beneficiary> saveList = apiBeneficiaryInfoDtoList.stream().map(dto -> {
                    Beneficiary beneficiary = new Beneficiary();
                    BeanUtils.copyProperties(dto,beneficiary);
                    return beneficiary;
                }).collect(Collectors.toList());
                iBeneficiaryService.saveOrUpdateBatch(saveList);
            }

            return Result.success();

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


    /**
     * 校验预约附件信息是否存在
     * @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);
    }
}
