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

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.google.gson.reflect.TypeToken;
import com.yd.auth.core.dto.AuthUserDto;
import com.yd.auth.core.utils.SecurityUtil;
import com.yd.common.constant.CodeGeneratorConstants;
import com.yd.common.enums.CommonEnum;
import com.yd.common.enums.ResultCode;
import com.yd.common.exception.BusinessException;
import com.yd.common.result.Result;
import com.yd.common.utils.CodeGenerator;
import com.yd.common.utils.RandomStringGenerator;
import com.yd.csf.api.service.*;
import com.yd.csf.feign.dto.appointment.*;
import com.yd.csf.feign.dto.appointmentfile.ApiAppointmentFileDto;
import com.yd.csf.feign.request.appointment.*;
import com.yd.csf.feign.response.appointment.*;
import com.yd.csf.service.dao.AppointmentMapper;
import com.yd.csf.service.dto.PolicySigner;
import com.yd.csf.service.enums.AppointmentStatusEnum;
import com.yd.csf.service.enums.FnaStatusEnum;
import com.yd.csf.service.enums.PolicyFollowStatusEnum;
import com.yd.csf.service.enums.PolicyStatusEnum;
import com.yd.csf.service.model.*;
import com.yd.csf.service.service.*;
import com.yd.csf.service.utils.GSONUtil;
import com.yd.oss.feign.client.ApiRelObjectMaterialFeignClient;
import com.yd.oss.feign.dto.ApiRelMaterialDto;
import com.yd.oss.feign.request.ApiRelObjectMaterialListAddRequest;
import com.yd.question.feign.client.ApiQuestionnairesFeignClient;
import com.yd.question.feign.request.ApiAnswerSaveRequest;
import com.yd.question.feign.request.ApiBatchSaveAnswerRequest;
import com.yd.question.feign.request.ApiObjectSaveRequest;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.ObjectUtils;
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 javax.annotation.Resource;
import java.time.ZoneId;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Objects;
import java.util.stream.Collectors;

/**
 * 预约信息业务实现类
 */
@Slf4j
@Service
public class ApiAppointmentServiceImpl implements ApiAppointmentService {

    @Autowired
    private ApiAppointmentCheckService apiAppointmentCheckService;

    @Autowired
    private ApiProductPlanService apiProductPlanService;

    @Autowired
    private ApiAdditionalService apiAdditionalService;

    @Autowired
    private ApiPolicyholderService apiPolicyholderService;

    @Autowired
    private ApiInsurantService apiInsurantService;

    @Autowired
    private ApiBeneficiaryService apiBeneficiaryService;

    @Autowired
    private ApiSecondHolderService apiSecondHolderService;

    @Autowired
    private IAppointmentService iAppointmentService;

    @Autowired
    private ApiAppointmentFileService apiAppointmentFileService;

    @Autowired
    private FnaService fnaService;

    @Autowired
    private ApiAppointmentReferrerService appointmentReferrerService;

    @Autowired
    private ApiAppointmentLogService appointmentLogService;

    @Autowired
    private ApiAppointmentReferrerLogService apiAppointmentReferrerLogService;

    @Autowired
    private ApiAppointmentUserSignService apiAppointmentUserSignService;

    @Autowired
    private ApiAppointmentUserSignLogService apiAppointmentUserSignLogService;

    @Autowired
    private IAppointmentLogService iAppointmentLogService;

    @Autowired
    private IAppointmentReferrerLogService iAppointmentReferrerLogService;

    @Autowired
    private IAppointmentUserSignLogService iAppointmentUserSignLogService;

    @Autowired
    private ApiQuestionnairesFeignClient apiQuestionnairesFeignClient;

    @Autowired
    private ApiRelObjectMaterialFeignClient apiRelObjectMaterialFeignClient;

    @Autowired
    private PolicyFollowService policyFollowService;
    @Resource
    private PolicyService policyService;
    @Resource
    private PolicyPolicyholderService policyPolicyholderService;
    @Resource
    private PolicyInsurantService policyInsurantService;
    @Resource
    private PolicyBeneficiaryService policyBeneficiaryService;
    @Resource
    private PolicySecondHolderService policySecondHolderService;
    @Resource
    private PolicyAdditionalService policyAdditionalService;
    @Resource
    private IProductPlanService iProductPlanService;
    @Resource
    private CustomerService customerService;
    @Resource
    private FnaFormService fnaFormService;
    @Resource
    private PolicyBrokerService policyBrokerService;
    @Resource
    private PolicyAppointmentFileService policyAppointmentFileService;
    @Resource
    private AppointmentMapper appointmentMapper;

    /**
     * 预约分页查询
     *
     * @param request
     * @return
     */
    @Override
    public Result<IPage<ApiAppointmentPageResponse>> page(ApiAppointmentPageRequest request) {
        Page<ApiAppointmentPageResponse> page = new Page<>(request.getPageNo(), request.getPageSize());
        IPage<ApiAppointmentPageResponse> iPage = iAppointmentService.page(page, request);
        return Result.success(iPage);
    }

    /**
     * 预约详情（聚合信息详情）
     *
     * @param appointmentBizId
     * @return
     */
    @Override
    public Result<ApiAppointmentDetailResponse> detail(String appointmentBizId) {
        ApiAppointmentDetailResponse response = new ApiAppointmentDetailResponse();
        //预约主体信息详情（单个对象详情）
        Result<Appointment> result = checkAppointmentIsExist(appointmentBizId);
        Appointment appointment = result.getData();
        ApiAppointmentInfoDto dto = new ApiAppointmentInfoDto();
        BeanUtils.copyProperties(appointment, dto);
        dto.setReferrerDtoList(appointmentReferrerService.referrerDtoList(appointmentBizId));
        dto.setUserSignDtoList(apiAppointmentUserSignService.userSignDtoList(appointmentBizId));
        response.setApiAppointmentInfoDto(dto);
        //产品计划信息
        Result<ApiProductPlanInfoDto> result1 = apiProductPlanService.detail(appointmentBizId, "");
        response.setApiProductPlanInfoDto(result1.getData());
        //投保人信息
        Result<ApiPolicyholderInfoDto> result2 = apiPolicyholderService.detail(appointmentBizId, "");
        response.setApiPolicyholderInfoDto(result2.getData());
        //受保人信息
        Result<ApiInsurantInfoDto> result3 = apiInsurantService.detail(appointmentBizId, "");
        response.setApiInsurantInfoDto(result3.getData());
        //受益人列表信息
        ApiBeneficiaryInfoFzDto apiBeneficiaryInfoFzDto = new ApiBeneficiaryInfoFzDto();
        apiBeneficiaryInfoFzDto.setIsLegalBeneficiary(appointment.getIsLegalBeneficiary());
        Result<List<ApiBeneficiaryInfoDto>> result4 = apiBeneficiaryService.list(appointmentBizId);
        apiBeneficiaryInfoFzDto.setApiBeneficiaryInfoDtoList(result4.getData());
        response.setApiBeneficiaryInfoFzDto(apiBeneficiaryInfoFzDto);
        //第二持有人信息
        Result<ApiSecondHolderInfoDto> result5 = apiSecondHolderService.detail(appointmentBizId, "");
        response.setApiSecondHolderInfoDto(result5.getData());
        //预约附件信息列表
        Result<List<ApiAppointmentFileDto>> result6 = apiAppointmentFileService.list(appointmentBizId);
        response.setApiAppointmentFileDtoList(result6.getData());
        response.setStatus(!Objects.isNull(result.getData()) ? appointment.getStatus() : null);

        //获取问卷详细信息-单个问卷详细信息
//        Result<ApiQuestionnairesDetailResponse> responseResult = apiQuestionnairesFeignClient.detail("questionnaires_1001",appointmentBizId);
//        response.setQuestionnairesDetailResponse(responseResult.getData());
        return Result.success(response);
    }

    /**
     * 预约主体信息详情（单个对象详情）
     *
     * @param appointmentBizId
     * @return
     */
    @Override
    public Result<ApiAppointmentInfoDto> mainDetail(String appointmentBizId) {
        Result<Appointment> result = checkAppointmentIsExist(appointmentBizId);
        Appointment appointment = result.getData();
        ApiAppointmentInfoDto dto = new ApiAppointmentInfoDto();
        BeanUtils.copyProperties(appointment, dto);
        return Result.success(dto);
    }

    /**
     * 新增预约提交
     *
     * @param request
     * @return
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public Result<ApiAppointmentAddResponse> add(ApiAppointmentAddRequest request) {

        //新增预约-添加预约信息主表数据 - 预约状态为待预约
        if (Objects.isNull(request.getApiAppointmentInfoDto())) {
            request.setApiAppointmentInfoDto(new ApiAppointmentInfoDto());
        }
        //提交 ——>流转状态为预约中
        Result<Appointment> appointmentResult = addAppointmentData(
                request.getApiAppointmentInfoDto(),
                AppointmentStatusEnum.YYZ.getItemValue(),
                request.getApiBeneficiaryInfoFzDto().getIsLegalBeneficiary());

        Appointment appointment = appointmentResult.getData();
        //添加预约日志信息
        Result<String> result = appointmentLogService.saveAppointmentLog(appointment);
        //添加陪同转介人信息列表
        appointmentReferrerService.saveAppointmentReferrerList(request.getApiAppointmentInfoDto().getReferrerDtoList(),appointment.getAppointmentBizId());
        //添加预约-陪同转介人日志信息
        apiAppointmentReferrerLogService.saveAppointmentReferrerLogList(request.getApiAppointmentInfoDto().getReferrerDtoList(), result.getData());
        //添加签单员列表信息
        apiAppointmentUserSignService.saveAppointmentUserSignList(request.getApiAppointmentInfoDto().getUserSignDtoList(),appointment.getAppointmentBizId());
        //添加预约-签单员列表信息日志
        apiAppointmentUserSignLogService.saveAppointmentUserSignLogList(request.getApiAppointmentInfoDto().getUserSignDtoList(),result.getData());

        //添加产品计划信息表数据
        Result<ProductPlan> productPlanResult = apiProductPlanService.addProductPlanData(request.getApiProductPlanInfoDto(), appointment.getAppointmentBizId());
        ProductPlan productPlan = productPlanResult.getData();
        //批量添加产品计划-附加险信息表数据
        apiAdditionalService.batchAddAdditionalData(request.getApiProductPlanInfoDto(), productPlan.getPlanBizId());
        //添加投保人信息表数据
        apiPolicyholderService.addPolicyholderData(request.getApiPolicyholderInfoDto(), appointment.getAppointmentBizId());
        //添加受保人信息表数据
        apiInsurantService.addInsurantData(request.getApiInsurantInfoDto(), appointment.getAppointmentBizId());
        //批量添加受益人信息表数据
        apiBeneficiaryService.batchAddBeneficiaryData(request.getApiBeneficiaryInfoFzDto().getApiBeneficiaryInfoDtoList(), appointment.getAppointmentBizId());
        //添加第二持有人信息表数据
        apiSecondHolderService.addSecondHolderData(request.getApiSecondHolderInfoDto(), appointment.getAppointmentBizId());
        //新增健康问卷和预约对象关系绑定，和答题提交
        objectSaveJkQuestion(appointment.getAppointmentBizId(),request.getApiAnswerSaveRequest());
        //新增对象材料关系信息
        addRelObjectMaterialList(appointment.getAppointmentBizId(),request.getMaterialDtoList());
        //预约编号和预约业务id更新到FNA表（提交待预约状态，预约信息的预约业务id和预约编号更新到Fna表的预约业务id和预约编号）
        updateFnaBizIdAndNo(appointment.getFnaBizId(), appointment.getAppointmentBizId(), appointment.getAppointmentNo());
        ApiAppointmentAddResponse response = new ApiAppointmentAddResponse();
        response.setAppointmentBizId(appointment.getAppointmentBizId());
        return Result.success(response);
    }

    /**
     * 新增对象材料关系信息
     * @param appointmentBizId
     * @return
     */
    public Result addRelObjectMaterialList(String appointmentBizId,
                                           List<ApiAppointmentMaterialDto> dtoList) {
        //添加-单个对象和材料列表关系信息
        ApiRelObjectMaterialListAddRequest addRequest = new ApiRelObjectMaterialListAddRequest();
        addRequest.setObjectBizId(appointmentBizId);
        addRequest.setObjectName(CommonEnum.UID_TYPE_APPOINTMENT.getName());
        addRequest.setObjectTableName(CommonEnum.UID_TYPE_APPOINTMENT.getCode());
        addRequest.setObjectType(CommonEnum.UID_TYPE_APPOINTMENT.getCode());
        if (!CollectionUtils.isEmpty(dtoList)) {
            List<ApiRelMaterialDto> materialDtoList = dtoList.stream().map(d -> {
                ApiRelMaterialDto materialDto = new ApiRelMaterialDto();
                materialDto.setFileBizIdList(d.getFileBizIdList());
                materialDto.setMaterialBizId(d.getMaterialBizId());
                return materialDto;
            }).collect(Collectors.toList());
            addRequest.setMaterialDtoList(materialDtoList);
        }
        apiRelObjectMaterialFeignClient.addRelObjectMaterialList(addRequest);
        return Result.success();
    }

    /**
     * 提交待预约状态，预约信息更新到Fna表的预约业务id和预约编号
     *
     * @return
     */
    @Transactional(rollbackFor = Exception.class)
    public Result updateFnaBizIdAndNo(String fnaBizId, String appointmentBizId, String appointmentNo) {
        Fna fna = fnaService.queryOne(fnaBizId);
        if (!Objects.isNull(fna)) {
            //预约编号
            fna.setAppointmentBizId(appointmentBizId);
            fna.setAppointmentNo(appointmentNo);
            fnaService.saveOrUpdate(fna);
        }
        return Result.success();
    }

    /**
     * 新增预约暂存
     * @param request
     * @return
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public Result addStorage(ApiAppointmentAddStorageRequest request) {
        if (Objects.isNull(request.getApiAppointmentInfoDto())) {
            request.setApiAppointmentInfoDto(new ApiAppointmentInfoDto());
        }
        if (Objects.isNull(request.getApiBeneficiaryInfoFzDto())) {
            request.setApiBeneficiaryInfoFzDto(new ApiBeneficiaryInfoFzDto());
        }
        apiAppointmentCheckService.checkCustomerAndFna(request.getApiAppointmentInfoDto(), "预约信息-");

        //新增预约暂存-添加预约信息主表数据为待完善状态
        Result<Appointment> appointmentResult = addAppointmentData(request.getApiAppointmentInfoDto(),
                AppointmentStatusEnum.DWS.getItemValue(),
                request.getApiBeneficiaryInfoFzDto().getIsLegalBeneficiary());
        Appointment appointment = appointmentResult.getData();
        //添加预约日志信息
        Result<String> result = appointmentLogService.saveAppointmentLog(appointment);
        //添加陪同转介人信息列表
        appointmentReferrerService.saveAppointmentReferrerList(request.getApiAppointmentInfoDto().getReferrerDtoList(),appointment.getAppointmentBizId());
        //添加预约-陪同转介人日志信息
        apiAppointmentReferrerLogService.saveAppointmentReferrerLogList(request.getApiAppointmentInfoDto().getReferrerDtoList(), result.getData());
        //添加签单员列表信息
        apiAppointmentUserSignService.saveAppointmentUserSignList(request.getApiAppointmentInfoDto().getUserSignDtoList(),appointment.getAppointmentBizId());
        //添加预约-签单员列表信息日志
        apiAppointmentUserSignLogService.saveAppointmentUserSignLogList(request.getApiAppointmentInfoDto().getUserSignDtoList(),result.getData());

        //添加产品计划信息表数据
        Result<ProductPlan> productPlanResult = apiProductPlanService.addProductPlanData(request.getApiProductPlanInfoDto(), appointment.getAppointmentBizId());
        ProductPlan productPlan = productPlanResult.getData();
        //批量添加产品计划-附加险信息表数据
        apiAdditionalService.batchAddAdditionalData(request.getApiProductPlanInfoDto(), productPlan.getPlanBizId());
        //添加投保人信息表数据
        apiPolicyholderService.addPolicyholderData(request.getApiPolicyholderInfoDto(), appointment.getAppointmentBizId());
        //添加受保人信息表数据
        apiInsurantService.addInsurantData(request.getApiInsurantInfoDto(), appointment.getAppointmentBizId());
        //批量添加受益人信息表数据
        apiBeneficiaryService.batchAddBeneficiaryData(request.getApiBeneficiaryInfoFzDto().getApiBeneficiaryInfoDtoList(), appointment.getAppointmentBizId());
        //添加第二持有人信息表数据
        apiSecondHolderService.addSecondHolderData(request.getApiSecondHolderInfoDto(), appointment.getAppointmentBizId());
        //预约编号和预约业务id更新到FNA表（提交待预约状态，预约信息的预约业务id和预约编号更新到Fna表的预约业务id和预约编号）
        updateFnaBizIdAndNo(appointment.getFnaBizId(), appointment.getAppointmentBizId(), appointment.getAppointmentNo());
        //新增健康问卷和预约对象关系绑定
        objectSaveJkQuestion(appointment.getAppointmentBizId(),request.getApiAnswerSaveRequest());
        //新增对象材料关系信息
        addRelObjectMaterialList(appointment.getAppointmentBizId(),request.getMaterialDtoList());
        return Result.success();
    }

    /**
     * 新增预约-添加预约信息主表数据
     *
     * @param dto
     * @return
     */
    @Transactional(rollbackFor = Exception.class)
    public Result<Appointment> addAppointmentData(ApiAppointmentInfoDto dto,
                                                  Integer status,
                                                  Integer isLegalBeneficiary) {
        if (Objects.isNull(dto)) {
            //为空设置，方便新建暂存公用方法
            dto = new ApiAppointmentInfoDto();
        }
        //获取Security上下文当前用户的登录信息
        AuthUserDto authUserDto = SecurityUtil.getCurrentLoginUser();
        Appointment appointment = new Appointment();
        BeanUtils.copyProperties(dto, appointment);
        //生成预约信息主表唯一业务ID
        appointment.setAppointmentBizId(RandomStringGenerator.generateBizId16(CommonEnum.UID_TYPE_APPOINTMENT.getCode()));
        //生成预约编号
        appointment.setAppointmentNo(CodeGenerator.generateCode(CodeGeneratorConstants.APPOINTMENT));
        //预约状态
        appointment.setStatus(status);
        appointment.setCreatorName(authUserDto.getUsername());
        appointment.setIsLegalBeneficiary(isLegalBeneficiary);
        iAppointmentService.saveOrUpdate(appointment);
        return Result.success(appointment);
    }

    /**
     * 编辑预约提交 (聚合信息编辑预约提交)
     *
     * @param request
     * @return
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public Result edit(ApiAppointmentEditRequest request) {

        Integer oldStatus = null;
        Integer newStatus = null;
        Appointment appointmentCheck = null;
        if (!Objects.isNull(request.getApiAppointmentInfoDto())) {
            //校验预约信息是否存在
            Result<Appointment> result = checkAppointmentIsExist(request.getApiAppointmentInfoDto().getAppointmentBizId());
            appointmentCheck = result.getData();
            oldStatus = appointmentCheck.getStatus();
            if (AppointmentStatusEnum.DWS.getItemValue().equals(appointmentCheck.getStatus())) {
                //当前为待完善状态——>状态更新为预约中
                newStatus = AppointmentStatusEnum.YYZ.getItemValue();
            }else if (AppointmentStatusEnum.YQX.getItemValue().equals(appointmentCheck.getStatus())) {
                //当前为已取消状态——>状态更新为预约中
                newStatus = AppointmentStatusEnum.YYZ.getItemValue();
            }else if (AppointmentStatusEnum.YYZ.getItemValue().equals(appointmentCheck.getStatus())) {
                if (request.getSource() == 2) {
                    //当前生成新单跟进提交：
                    //当前状态为预约中 ——> 状态更新为预约成功 ——> 新增新单跟进记录
                    newStatus = AppointmentStatusEnum.YY_CG.getItemValue();
                }
            }
        }

        //编辑预约提交-编辑预约信息主表数据
        if (Objects.isNull(request.getApiAppointmentInfoDto())) {
            request.setApiAppointmentInfoDto(new ApiAppointmentInfoDto());
        }
        Result<Appointment> appointmentResult = editAppointmentData(request.getApiAppointmentInfoDto(),
                newStatus,
                request.getApiBeneficiaryInfoFzDto().getIsLegalBeneficiary());

        Appointment appointment = appointmentResult.getData();
        //添加预约日志信息
        Result<String> result = appointmentLogService.saveAppointmentLog(appointmentResult.getData());
        //添加陪同转介人信息列表
        appointmentReferrerService.saveAppointmentReferrerList(request.getApiAppointmentInfoDto().getReferrerDtoList(),appointment.getAppointmentBizId());
        //添加预约-陪同转介人日志信息
        apiAppointmentReferrerLogService.saveAppointmentReferrerLogList(request.getApiAppointmentInfoDto().getReferrerDtoList(), result.getData());
        //添加签单员列表信息
        apiAppointmentUserSignService.saveAppointmentUserSignList(request.getApiAppointmentInfoDto().getUserSignDtoList(),appointment.getAppointmentBizId());
        //添加预约-签单员列表信息日志
        apiAppointmentUserSignLogService.saveAppointmentUserSignLogList(request.getApiAppointmentInfoDto().getUserSignDtoList(),result.getData());

        //编辑产品计划信息表数据
        Result<ProductPlan> productPlanResult = apiProductPlanService.editProductPlanData(request.getApiProductPlanInfoDto(), appointment.getAppointmentBizId());
        ProductPlan productPlan = productPlanResult.getData();
        //批量编辑产品计划-附加险信息表数据
        apiAdditionalService.batchEditAdditionalData(request.getApiProductPlanInfoDto(), productPlan.getPlanBizId());
        //编辑投保人信息表数据
        apiPolicyholderService.editPolicyholderData(request.getApiPolicyholderInfoDto(), appointment.getAppointmentBizId());
        //编辑受保人信息表数据
        apiInsurantService.editInsurantData(request.getApiInsurantInfoDto(), appointment.getAppointmentBizId());
        //批量编辑受益人信息表数据
        apiBeneficiaryService.batchEditBeneficiaryData(request.getApiBeneficiaryInfoFzDto().getApiBeneficiaryInfoDtoList(), appointment.getAppointmentBizId());
        //编辑第二持有人信息表数据
        apiSecondHolderService.editSecondHolderData(request.getApiSecondHolderInfoDto(), appointment.getAppointmentBizId());

        //远程调用-问卷-答题提交接口
        if (!Objects.isNull(request.getApiAnswerSaveRequest()) && !CollectionUtils.isEmpty(request.getApiAnswerSaveRequest().getAnswerSessionsDtoList())) {
            ApiAnswerSaveRequest answerSaveRequest = new ApiAnswerSaveRequest();
            answerSaveRequest.setObjectBizId(appointment.getAppointmentBizId());
            answerSaveRequest.setQuestionnaireBizId("questionnaires_1001");
            answerSaveRequest.setAnswerSessionsDtoList(request.getApiAnswerSaveRequest().getAnswerSessionsDtoList());
            apiQuestionnairesFeignClient.answerSave(answerSaveRequest);
        }

        if (!Objects.isNull(oldStatus)
                && AppointmentStatusEnum.YYZ.getItemValue().equals(oldStatus)
                && request.getSource() == 2) {
            //生成新单跟进提交
            //当前状态为预约中 ——> 状态更新为预约成功 ——> 更新FNA预约业务id和预约编号、新增新单跟进记录
            //更新FNA预约业务id和预约编号
            updateFnaBizIdAndNo(appointment.getFnaBizId(), appointment.getAppointmentBizId(), appointment.getAppointmentNo());
            //新增新单跟进记录
            savePolicyFollow(appointment);
            //更新关联的FNA状态为"待签单"
            updateFnaStatusToPendingSignature(appointment.getFnaBizId());
        }
        return Result.success();
    }

    /**
     * 更新关联的FNA状态为"待签单"
     * @param fnaBizId FNA业务ID
     */
    private void updateFnaStatusToPendingSignature(String fnaBizId) {
        if (StringUtils.isBlank(fnaBizId)) {
            return;
        }
        Fna fna = fnaService.queryOne(fnaBizId);
        if (fna != null) {
            // 更新为"待签单"
            fnaService.updateFnaStatus(fnaBizId, FnaStatusEnum.PENDING_SIGNATURE.getItemValue());
        }
    }

    /**
     * 编辑预约暂存 (聚合信息编辑预约暂存)
     * @param request
     * @return
     */
    @Override
    public Result editStorage(ApiAppointmentEditStorageRequest request) {
        //校验预约信息-客户和fna入参
        apiAppointmentCheckService.checkCustomerAndFna(request.getApiAppointmentInfoDto(), "预约信息-");

        //编辑预约提交-编辑预约信息主表数据
        if (Objects.isNull(request.getApiAppointmentInfoDto())) {
            request.setApiAppointmentInfoDto(new ApiAppointmentInfoDto());
        }
        if (Objects.isNull(request.getApiBeneficiaryInfoFzDto())) {
            request.setApiBeneficiaryInfoFzDto(new ApiBeneficiaryInfoFzDto());
        }

        Result<Appointment> appointmentResult = editAppointmentData(request.getApiAppointmentInfoDto(), null,request.getApiBeneficiaryInfoFzDto().getIsLegalBeneficiary());
        Appointment appointment = appointmentResult.getData();
        //添加预约日志信息
        Result<String> result = appointmentLogService.saveAppointmentLog(appointmentResult.getData());
        //添加陪同转介人信息列表
        appointmentReferrerService.saveAppointmentReferrerList(request.getApiAppointmentInfoDto().getReferrerDtoList(),appointment.getAppointmentBizId());
        //添加预约-陪同转介人日志信息
        apiAppointmentReferrerLogService.saveAppointmentReferrerLogList(request.getApiAppointmentInfoDto().getReferrerDtoList(), result.getData());
        //添加签单员列表信息
        apiAppointmentUserSignService.saveAppointmentUserSignList(request.getApiAppointmentInfoDto().getUserSignDtoList(),appointment.getAppointmentBizId());
        //添加预约-签单员列表信息日志
        apiAppointmentUserSignLogService.saveAppointmentUserSignLogList(request.getApiAppointmentInfoDto().getUserSignDtoList(),result.getData());

        //编辑产品计划信息表数据
        Result<ProductPlan> productPlanResult = apiProductPlanService.editProductPlanData(request.getApiProductPlanInfoDto(), appointment.getAppointmentBizId());
        ProductPlan productPlan = productPlanResult.getData();
        //批量编辑产品计划-附加险信息表数据
        apiAdditionalService.batchEditAdditionalData(request.getApiProductPlanInfoDto(), productPlan.getPlanBizId());
        //编辑投保人信息表数据
        apiPolicyholderService.editPolicyholderData(request.getApiPolicyholderInfoDto(), appointment.getAppointmentBizId());
        //编辑受保人信息表数据
        apiInsurantService.editInsurantData(request.getApiInsurantInfoDto(), appointment.getAppointmentBizId());
        //批量编辑受益人信息表数据
        apiBeneficiaryService.batchEditBeneficiaryData(request.getApiBeneficiaryInfoFzDto().getApiBeneficiaryInfoDtoList(), appointment.getAppointmentBizId());
        //编辑第二持有人信息表数据
        apiSecondHolderService.editSecondHolderData(request.getApiSecondHolderInfoDto(), appointment.getAppointmentBizId());

        //远程调用-问卷-答题提交接口
        if (!CollectionUtils.isEmpty(request.getAnswerSessionsDtoList())) {
            ApiAnswerSaveRequest answerSaveRequest = new ApiAnswerSaveRequest();
            answerSaveRequest.setObjectBizId(appointment.getAppointmentBizId());
            answerSaveRequest.setQuestionnaireBizId("questionnaires_1001");
            answerSaveRequest.setAnswerSessionsDtoList(request.getAnswerSessionsDtoList());
            apiQuestionnairesFeignClient.answerSave(answerSaveRequest);
        }
        return Result.success();
    }

    /**
     * 确定预约时间提交 (流程流转到新单跟进)
     *
     * @param request
     * @return
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public Result editConfirmTime(ApiAppointmentEditConfirmTimeRequest request) {
        //校验预约信息是否存在
//        Result<Appointment> result = checkAppointmentIsExist(request.getAppointmentBizId());
//        Appointment appointment = result.getData();
//        if (!AppointmentStatusEnum.DYY.getItemValue().equals(appointment.getStatus())) {
//            //非待预约状态，不能更新
//            if (AppointmentStatusEnum.ZC.getItemValue().equals(appointment.getStatus())) {
//                //暂存
//                throw new BusinessException("当前为暂存状态，不能提交到新单跟进！");
//            } else {
//                //其他状态
//                throw new BusinessException("你已经提交到新单跟进，不能再次提交！");
//            }
//        }
//        appointment.setConfirmAppointmentTime(request.getConfirmAppointmentTime());
//        //流转到新单跟进（这里的预约状态为待签署）
//        appointment.setStatus(AppointmentStatusEnum.DQS.getItemValue());
//        iAppointmentService.saveOrUpdate(appointment);
//
//        //确定预约时间提交 (流程流转到新单跟进) - 新增新单跟进记录
//        savePolicyFollow(appointment);
        return Result.success();
    }

    /**
     * 确定预约时间提交 (流程流转到新单跟进) - 新增新单跟进记录
     *
     * @return
     */
    @Transactional(rollbackFor = Exception.class)
    public Result savePolicyFollow(Appointment appointment) {
        Result<ApiAppointmentDetailResponse> result = detail(appointment.getAppointmentBizId());
        ApiAppointmentDetailResponse response = result.getData();
        // 获取入参
        ApiProductPlanMainInfoDto apiProductPlanMainInfoDto = null;
        List<ApiProductPlanAdditionalInfoDto> apiProductPlanAdditionalInfoDtoList = new ArrayList<>();
        ApiPolicyholderInfoDto apiPolicyholderInfoDto = null;
        ApiInsurantInfoDto apiInsurantInfoDto = null;
        List<ApiBeneficiaryInfoDto> apiBeneficiaryInfoDtoList = null;
        ApiSecondHolderInfoDto apiSecondHolderInfoDto = null;
        List<ApiAppointmentFileDto> apiAppointmentFileDtoList = null;
        String policyTransfer = null;
        if (!Objects.isNull(response)
                && !Objects.isNull(response.getApiProductPlanInfoDto())
                && !Objects.isNull(response.getApiProductPlanInfoDto().getApiProductPlanMainInfoDto())) {
            apiProductPlanMainInfoDto = response.getApiProductPlanInfoDto().getApiProductPlanMainInfoDto();
            //转保声明选项(字典)
            policyTransfer = response.getApiAppointmentInfoDto().getPolicyTransfer();
            // 产品计划附加险列表
            apiProductPlanAdditionalInfoDtoList = response.getApiProductPlanInfoDto().getApiProductPlanAdditionalInfoDtoList();
            // 投保人
            apiPolicyholderInfoDto = response.getApiPolicyholderInfoDto();
            // 受保人
            apiInsurantInfoDto = response.getApiInsurantInfoDto();
            // 受益人列表信息
            apiBeneficiaryInfoDtoList = response.getApiBeneficiaryInfoFzDto().getApiBeneficiaryInfoDtoList();
            // 第二持有人
            apiSecondHolderInfoDto = response.getApiSecondHolderInfoDto();
            // 预约附件信息列表
            apiAppointmentFileDtoList = response.getApiAppointmentFileDtoList();
        }
        if (!Objects.isNull(response)
                && !Objects.isNull(response.getApiInsurantInfoDto())) {
            apiInsurantInfoDto = response.getApiInsurantInfoDto();
        }
        // 查询客户信息表数据
        Customer customer = customerService.getByCustomerBizId(appointment.getCustomerBizId());
        // 查询产品计划信息表数据
        ProductPlan productPlan = iProductPlanService.queryOne(appointment.getAppointmentBizId(), apiProductPlanMainInfoDto.getPlanBizId());

        // 新增新单跟进记录
        PolicyFollow follow = new PolicyFollow();
        String policyBizId = RandomStringGenerator.generateBizId16(CommonEnum.UID_TYPE_POLICY.getCode());
        //新单跟进唯一业务ID
        follow.setPolicyBizId(policyBizId);
        follow.setFnaBizId(appointment.getFnaBizId());
        follow.setAppointmentBizId(appointment.getAppointmentBizId());
        follow.setAppointmentNo(appointment.getAppointmentNo());
        //客户信息表唯一业务ID
        follow.setCustomerBizId(appointment.getCustomerBizId());
        if (customer != null) {
            //客户名称
            follow.setCustomerName(customer.getNamePyEn());
        }
        //待签单
        follow.setStatus(PolicyFollowStatusEnum.PENDING_SIGN.getItemValue());
        follow.setNextStatusList(policyFollowService.getNextStatus(PolicyFollowStatusEnum.PENDING_SIGN));

        // 从预约信息获取备注
        if (appointment.getRemark() != null) {
            follow.setRemark(appointment.getRemark());
        }

        // 从预约信息获取签单日期
        if (appointment.getSignDate() != null) {
            follow.setSignDate(Date.from(appointment.getSignDate().atZone(ZoneId.systemDefault()).toInstant()));
        }

        // 从预约信息获取签单地点（优先使用签单地址，否则使用会面地点）
        if (appointment.getSigningAddress() != null) {
            follow.setSignLocation(appointment.getSigningAddress());
        } else if (appointment.getMeetingPoint() != null) {
            follow.setSignLocation(appointment.getMeetingPoint());
        }

        // 保單持有人
        if (apiPolicyholderInfoDto != null) {
            follow.setPolicyHolder(apiPolicyholderInfoDto.getNameCn());
        }

        // 受保人信息
        if (!Objects.isNull(apiInsurantInfoDto)) {
            // 受保人
            follow.setInsured(apiInsurantInfoDto.getNameCn());
            // 受保人业务id
            follow.setInsuredBizId(apiInsurantInfoDto.getInsurantBizId());
            // 受保人与保單持有人关系
            if ("MYSELF".equals(apiInsurantInfoDto.getPolicyholderRel())) {
                follow.setInsured(follow.getPolicyHolder());
            }
            // 受保人年龄
            if (StringUtils.isNotBlank(apiInsurantInfoDto.getAge())) {
                follow.setInsuredAge(Integer.valueOf(apiInsurantInfoDto.getAge()));
            }
        }

        // 从签单员列表获取第一个签单人信息
        if (response.getApiAppointmentInfoDto() != null
                && response.getApiAppointmentInfoDto().getUserSignDtoList() != null
                && !response.getApiAppointmentInfoDto().getUserSignDtoList().isEmpty()) {
            ApiAppointmentUserSignDto firstSigner = response.getApiAppointmentInfoDto().getUserSignDtoList().get(0);
            follow.setSigner(firstSigner.getName());
            follow.setSignerBizId(firstSigner.getAppointmentUserSignBizId());
            follow.setPracticeCode(firstSigner.getPracticeCode());
        }

        // 产品计划信息
        if (!Objects.isNull(apiProductPlanMainInfoDto)) {
            // 产品上架信息表唯一业务ID
            follow.setProductLaunchBizId(apiProductPlanMainInfoDto.getProductLaunchBizId());
            // 产品名称
            follow.setProductName(apiProductPlanMainInfoDto.getProductLaunchMainName());
            // 产品类别（保险险种名称）
            follow.setProductCate(apiProductPlanMainInfoDto.getInsuranceTypeName());
            follow.setInsuranceCategoryBizId(apiProductPlanMainInfoDto.getInsuranceTypeId());
            follow.setCategoryCode(productPlan.getInsuranceTypeCode());
            // 保险公司
            follow.setInsuranceCompany(apiProductPlanMainInfoDto.getCompanyName());
            // 保险公司业务ID（从产品计划获取的公司ID）
            follow.setInsuranceCompanyBizId(apiProductPlanMainInfoDto.getCompanyId());
            // 对账公司
            follow.setReconciliationCompany(apiProductPlanMainInfoDto.getReconciliationCompanyName());
            // 对账公司业务ID（从产品计划获取的对账公司ID）
            follow.setReconciliationCompanyBizId(apiProductPlanMainInfoDto.getReconciliationCompanyId());
            follow.setReconciliationCompanyCode(apiProductPlanMainInfoDto.getReconciliationCompanyCode());

            // 币种
            follow.setPolicyCurrency(apiProductPlanMainInfoDto.getPolicyCurrency());
            // 供款年期
            if (StringUtils.isNotBlank(apiProductPlanMainInfoDto.getIssueNumber())) {
                follow.setIssueNumber(apiProductPlanMainInfoDto.getIssueNumber());
            }
            // 保障期限
            if (StringUtils.isNotBlank(apiProductPlanMainInfoDto.getGuaranteePeriod())) {
                follow.setGuaranteePeriod(apiProductPlanMainInfoDto.getGuaranteePeriod());
            }
            // 保额（重疾险）
            follow.setSumInsured(apiProductPlanMainInfoDto.getSumInsured());
            // 付款频率
            follow.setPaymentFrequency(apiProductPlanMainInfoDto.getPaymentFrequency());
            // 每期保费
            follow.setEachIssuePremium(apiProductPlanMainInfoDto.getEachIssuePremium());
            // 首期保费（不含徽费，预缴保费）
            follow.setInitialPremium(apiProductPlanMainInfoDto.getEachIssuePremium());
            // 是否预缴
            follow.setIsPrepay(apiProductPlanMainInfoDto.getIsPrepay());
            // 是否追溯
            follow.setIsTraceable(apiProductPlanMainInfoDto.getIsTraceable());
            // 是否参加递增保障权益
            follow.setIsJoin(apiProductPlanMainInfoDto.getIsJoin());
            // 首期付款方式
            follow.setInitialPaymentMethod(apiProductPlanMainInfoDto.getInitialPaymentMethod());
            // 续期付款方式
            follow.setRenewalPaymentMethod(apiProductPlanMainInfoDto.getRenewalPaymentMethod());
            // 红利付款方式
            follow.setDividendDistributionMethod(apiProductPlanMainInfoDto.getDividendDistributionMethod());
            // 保单征费
            if (apiProductPlanMainInfoDto.getPolicyLevy() != null) {
                follow.setPolicyLevy(apiProductPlanMainInfoDto.getPolicyLevy().toString());
            }
        }

        policyFollowService.saveOrUpdate(follow);

        // 同步保存保单产品计划附加险
        savePolicyAdditional(apiProductPlanAdditionalInfoDtoList, policyBizId);
        // 同步转介人
        savePolicyBroker(appointment.getFnaBizId(), policyBizId);
        // 同步保存保单（产品计划）
        savePolicy(productPlan, apiPolicyholderInfoDto, apiInsurantInfoDto, policyBizId, policyTransfer);
        // 同步保存保单投保人
        savePolicyPolicyholder(apiPolicyholderInfoDto, policyBizId);
        // 同步保存保单受保人
        savePolicyInsurant(apiInsurantInfoDto, policyBizId);
        // 同步保存保单受益人
        savePolicyBeneficiary(apiBeneficiaryInfoDtoList, policyBizId);
        // 同步保存保单第二持有人
        savePolicySecondHolder(apiSecondHolderInfoDto, policyBizId);
        // 同步保存预约附件
        savePolicyAppointmentAttachment(apiAppointmentFileDtoList, policyBizId);

//        // 同步问卷信息
//        savePolicyQuestionnaire(appointment.getAppointmentBizId(), policyBizId);

        return Result.success();
    }

    private void savePolicyAppointmentAttachment(List<ApiAppointmentFileDto> apiAppointmentFileDtoList, String policyBizId) {
        if (ObjectUtils.isNotEmpty(apiAppointmentFileDtoList)) {
            List<PolicyAppointmentFile> policyAppointmentFileList = new ArrayList<>();
            apiAppointmentFileDtoList.forEach(apiAppointmentFileDto -> {
                PolicyAppointmentFile policyAppointmentFile = new PolicyAppointmentFile();
                BeanUtils.copyProperties(apiAppointmentFileDto, policyAppointmentFile);
                policyAppointmentFile.setId(null);
                policyAppointmentFile.setPolicyBizId(policyBizId);
                policyAppointmentFileList.add(policyAppointmentFile);
            });
            policyAppointmentFileService.saveOrUpdateBatch(policyAppointmentFileList);
        }
    }

    private void savePolicyBroker(String fnaBizId, String policyBizId) {
        log.info("同步保存保单转介人, fnaBizId: {}, policyBizId: {}", fnaBizId, policyBizId);

        QueryWrapper<FnaForm> queryWrapper = new QueryWrapper<>();
        queryWrapper.apply("fna_form_biz_id in (select fna_form_biz_id from fna where fna_biz_id = {0})", fnaBizId);
        FnaForm fnaForm = fnaFormService.getOne(queryWrapper);

        if (Objects.isNull(fnaForm)) {
            return;
        }
        // 转介人
        if (ObjectUtils.isNotEmpty(fnaForm.getBrokerList())) {
            List<PolicyBroker> brokerList = GSONUtil.fromJson((String) fnaForm.getBrokerList(), new TypeToken<List<PolicyBroker>>() {
            }.getType());

            log.info("转介人列表: {}", brokerList);

            if (ObjectUtils.isNotEmpty(brokerList)) {
                if (brokerList.get(0) != null && !Objects.isNull(brokerList.get(0).getPolicyBizId())) {
                    // 先删除旧的转介人
                    policyBrokerService.removeByPolicyBizId(brokerList.get(0).getPolicyBizId());
                }
                brokerList.forEach(broker -> {
                    broker.setPolicyBizId(policyBizId);
                });
                // 保存新的转介人
                policyBrokerService.saveOrUpdateBatch(brokerList);
            }
        }
    }

    private void setSignerList(PolicyFollow follow, Appointment appointment) {
        List<PolicySigner> signerList = new ArrayList<>();

        PolicySigner signer = new PolicySigner();
        if (!Objects.isNull(appointment.getBusinessNo())) {
            signer.setRegistrationNumber(appointment.getBusinessNo());
        }
        if (!Objects.isNull(appointment.getBusinessRepresentName1())) {
            signer.setSigner(appointment.getBusinessRepresentName1());
        }
        if (!Objects.isNull(appointment.getAccompanyMobileCode())) {
            signer.setMobileCode(appointment.getAccompanyMobileCode());
        }
        if (!Objects.isNull(appointment.getBusinessRepresentMobile1())) {
            signer.setPhone(appointment.getBusinessRepresentMobile1());
        }
        if (!Objects.isNull(appointment.getBusinessRepresentEmail1())) {
            signer.setEmail(appointment.getBusinessRepresentEmail1());
        }
        signerList.add(signer);

    }

    private void savePolicyQuestionnaire(String appointmentBizId, String policyBizId) {
        // 当前登录用户
        AuthUserDto currentLoginUser = SecurityUtil.getCurrentLoginUser();
        // 远程调用-问卷-答题提交接口
        ApiObjectSaveRequest apiObjectSaveRequest = new ApiObjectSaveRequest();
        apiObjectSaveRequest.setObjectBizId(policyBizId);
        apiObjectSaveRequest.setQuestionnaireBizId("questionnaires_1001");
        apiObjectSaveRequest.setObjectName("新单跟进");
        apiObjectSaveRequest.setObjectTableName("policy_follow");
        log.info("新单跟进-问卷-答题提交接口-请求参数: {}", apiObjectSaveRequest.toString());
        Result objectSaveResult = apiQuestionnairesFeignClient.objectSave(apiObjectSaveRequest);
        if (!Objects.isNull(objectSaveResult.getData())) {
            log.info("新单跟进-问卷-答题提交接口-返回结果: {}", objectSaveResult.toString());
        }
        // 查询问卷答案
        ApiBatchSaveAnswerRequest batchSaveAnswerRequest = new ApiBatchSaveAnswerRequest();
        batchSaveAnswerRequest.setOldObjectBizId(appointmentBizId);
        batchSaveAnswerRequest.setNewObjectBizId(policyBizId);
        batchSaveAnswerRequest.setQuestionnaireBizId("questionnaires_1001");
        batchSaveAnswerRequest.setCreatorId(currentLoginUser.getUserBizId());
        log.info("新单跟进-问卷-批量保存答案接口-请求参数: {}", batchSaveAnswerRequest.toString());
        Result batchSaveAnswer = apiQuestionnairesFeignClient.batchSaveAnswer(batchSaveAnswerRequest);
        if (!Objects.isNull(batchSaveAnswer.getData())) {
            log.info("新单跟进-问卷-批量保存答案接口-返回结果: {}", batchSaveAnswer.toString());
        }
    }

    private void savePolicyAdditional(List<ApiProductPlanAdditionalInfoDto> apiProductPlanAdditionalInfoDtoList, String policyBizId) {
        if (!CollectionUtils.isEmpty(apiProductPlanAdditionalInfoDtoList)) {
            apiProductPlanAdditionalInfoDtoList.forEach(apiProductPlanAdditionalInfoDto -> {
                PolicyAdditional policyAdditional = new PolicyAdditional();
                BeanUtils.copyProperties(apiProductPlanAdditionalInfoDto, policyAdditional);
                policyAdditional.setId(null);
                policyAdditional.setPolicyBizId(policyBizId);
                policyAdditional.setPolicyAdditionalBizId(RandomStringGenerator.generateBizId16("policy_additional"));
                policyAdditionalService.saveOrUpdate(policyAdditional);
            });
        }
    }

    private boolean savePolicySecondHolder(ApiSecondHolderInfoDto apiSecondHolderInfoDto, String policyBizId) {
        if (apiSecondHolderInfoDto == null) {
            return false;
        }
        PolicySecondHolder policySecondHolder = new PolicySecondHolder();
        BeanUtils.copyProperties(apiSecondHolderInfoDto, policySecondHolder);
        policySecondHolder.setId(null);
        policySecondHolder.setPolicyBizId(policyBizId);
        policySecondHolder.setPolicySecondHolderBizId(RandomStringGenerator.generateBizId16("policy_second_holder"));

        return policySecondHolderService.saveOrUpdate(policySecondHolder);
    }

    private boolean savePolicyBeneficiary(List<ApiBeneficiaryInfoDto> apiBeneficiaryInfoDtoList, String policyBizId) {
        if (CollectionUtils.isEmpty(apiBeneficiaryInfoDtoList)) {
            return false;
        }
        List<PolicyBeneficiary> policyBeneficiaryList = new ArrayList<>();
        for (ApiBeneficiaryInfoDto apiBeneficiaryInfoDto : apiBeneficiaryInfoDtoList) {
            PolicyBeneficiary policyBeneficiary = new PolicyBeneficiary();
            BeanUtils.copyProperties(apiBeneficiaryInfoDto, policyBeneficiary, "addressList");
//            if (!CollectionUtils.isEmpty(apiBeneficiaryInfoDto.getAddressList())) {
//                policyBeneficiary.setAddressList(GSONUtil.toJson(apiBeneficiaryInfoDto.getAddressList()));
//            }
            policyBeneficiary.setId(null);
            policyBeneficiary.setPolicyBizId(policyBizId);
            policyBeneficiary.setPolicyBeneficiaryBizId(RandomStringGenerator.generateBizId16("policy_beneficiary"));

            policyBeneficiaryList.add(policyBeneficiary);
        }
        return policyBeneficiaryService.saveBatch(policyBeneficiaryList);
    }

    private boolean savePolicyInsurant(ApiInsurantInfoDto apiInsurantInfoDto, String policyBizId) {
        if (apiInsurantInfoDto == null) {
            return false;
        }
        PolicyInsurant policyInsurant = new PolicyInsurant();
        BeanUtils.copyProperties(apiInsurantInfoDto, policyInsurant, "addressList");
        if (!CollectionUtils.isEmpty(apiInsurantInfoDto.getAddressList())) {
            policyInsurant.setAddressList(GSONUtil.toJson(apiInsurantInfoDto.getAddressList()));
        }
        policyInsurant.setId(null);
        policyInsurant.setPolicyBizId(policyBizId);
        policyInsurant.setPolicyInsurantBizId(RandomStringGenerator.generateBizId16("policy_insurant"));
        policyInsurant.setName(apiInsurantInfoDto.getNameCn());

        return policyInsurantService.saveOrUpdate(policyInsurant);
    }

    private boolean savePolicyPolicyholder(ApiPolicyholderInfoDto apiPolicyholderInfoDto, String policyBizId) {
        if (apiPolicyholderInfoDto == null) {
            return false;
        }
        PolicyPolicyholder policyPolicyholder = new PolicyPolicyholder();
        BeanUtils.copyProperties(apiPolicyholderInfoDto, policyPolicyholder, "addressList");
        if (!CollectionUtils.isEmpty(apiPolicyholderInfoDto.getAddressList())) {
            policyPolicyholder.setAddressList(GSONUtil.toJson(apiPolicyholderInfoDto.getAddressList()));
        }
        policyPolicyholder.setId(null);
        policyPolicyholder.setPolicyBizId(policyBizId);
        policyPolicyholder.setPolicyPolicyholderBizId(RandomStringGenerator.generateBizId16("policy_policyholder"));
        policyPolicyholder.setName(apiPolicyholderInfoDto.getNameCn());

        return policyPolicyholderService.saveOrUpdate(policyPolicyholder);
    }

    private boolean savePolicy(ProductPlan productPlan,
                               ApiPolicyholderInfoDto apiPolicyholderInfoDto,
                               ApiInsurantInfoDto apiInsurantInfoDto,
                               String policyBizId,
                               String policyTransfer
    ) {
        if (productPlan == null) {
            return false;
        }
        // 同步保存保单（产品计划）
        Policy policy = new Policy();
        BeanUtils.copyProperties(productPlan, policy);

        policy.setId(null);
        policy.setPolicyBizId(policyBizId);
        policy.setProductLaunchBizId(productPlan.getProductLaunchBizId());
        policy.setStatus(PolicyStatusEnum.INFORCE.getItemValue());
        // 投保人姓名
        if (Objects.nonNull(apiPolicyholderInfoDto)) {
            policy.setPolicyHolder(apiPolicyholderInfoDto.getNameCn());
        }
        // 被保人姓名
        if (Objects.nonNull(apiInsurantInfoDto)) {
            policy.setInsured(apiInsurantInfoDto.getNameCn());
        }
        // 保额
        policy.setSumInsured(productPlan.getSumInsured());
        // 供款年期
        policy.setPaymentTerm(productPlan.getIssueNumber());
        // 付款频率（字典）
        policy.setPaymentFrequency(productPlan.getPaymentFrequency());
        // 每期保费
        policy.setPaymentPremium(productPlan.getEachIssuePremium());
        // 首期保费（不含徽费，预缴保费）每期保费
        policy.setInitialPremium(productPlan.getEachIssuePremium());
        // 保险公司
        policy.setInsuranceCompany(productPlan.getCompanyName());
        // 是否预缴
        policy.setIsPrepaid(productPlan.getIsPrepay());
        // 转保声明选项(字典)
        policy.setPolicyTransfer(policyTransfer);

        policy.setCreateTime(new Date());
        policy.setUpdateTime(new Date());

        return policyService.saveOrUpdate(policy);
    }

    /**
     * 单个对象编辑-编辑预约主体信息
     *
     * @param apiAppointmentInfoDto
     * @return
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public Result singleEdit(ApiAppointmentInfoDto apiAppointmentInfoDto) {

        //编辑预约入参字段校验 - 预约信息字段校验
        apiAppointmentCheckService.checkEditApiAppointmentInfoDto(apiAppointmentInfoDto);

        //编辑预约-编辑预约信息主表数据
        Result<Appointment> appointmentResult = editAppointmentData(apiAppointmentInfoDto, null,null);
        //添加预约日志信息
        Result<String> result = appointmentLogService.saveAppointmentLog(appointmentResult.getData());
        //添加陪同转介人信息列表
        appointmentReferrerService.saveAppointmentReferrerList(apiAppointmentInfoDto.getReferrerDtoList(),apiAppointmentInfoDto.getAppointmentBizId());
        //添加预约-陪同转介人日志信息
        apiAppointmentReferrerLogService.saveAppointmentReferrerLogList(apiAppointmentInfoDto.getReferrerDtoList(), result.getData());
        //添加签单员列表信息
        apiAppointmentUserSignService.saveAppointmentUserSignList(apiAppointmentInfoDto.getUserSignDtoList(),apiAppointmentInfoDto.getAppointmentBizId());
        //添加预约-签单员列表信息日志
        apiAppointmentUserSignLogService.saveAppointmentUserSignLogList(apiAppointmentInfoDto.getUserSignDtoList(),result.getData());
        return Result.success();
    }

    /**
     * 编辑预约-编辑预约信息主表数据
     *
     * @param dto
     * @return
     */
    @Transactional(rollbackFor = Exception.class)
    public Result<Appointment> editAppointmentData(ApiAppointmentInfoDto dto, Integer status,Integer isLegalBeneficiary) {
        if (Objects.isNull(dto)) {
            //预约信息对象不能为空
            throw new BusinessException("预约信息对象不能为空");
        }
        if (StringUtils.isBlank(dto.getAppointmentBizId())) {
            throw new BusinessException("预约信息主表唯一业务ID不能为空");
        }
        //校验预约信息是否存在
        Result<Appointment> result = checkAppointmentIsExist(dto.getAppointmentBizId());
        Appointment appointment = result.getData();
        String appointmentNo = appointment.getAppointmentNo();

        BeanUtils.copyProperties(dto, appointment);
        if (!Objects.isNull(status)) {
            //不为空设置状态
            appointment.setStatus(status);
        }
        appointment.setAppointmentNo(appointmentNo);
        appointment.setIsLegalBeneficiary(isLegalBeneficiary);
        iAppointmentService.saveOrUpdate(appointment);
        return Result.success(appointment);
    }

    /**
     * 预约编辑关联FNA
     *
     * @param request
     * @return
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public Result editFna(ApiAppointmentEditFnaRequest request) {
        //校验预约信息是否存在
        Result<Appointment> result = checkAppointmentIsExist(request.getAppointmentBizId());
        Appointment appointment = result.getData();

        //修改预约信息表冗余的关联FNA业务id和关联FNA编号
        appointment.setFnaBizId(request.getFnaBizId());
        appointment.setFnaNo(request.getFnaNo());
        iAppointmentService.saveOrUpdate(appointment);
        return Result.success();
    }

    /**
     * 预约解除关联FNA
     *
     * @param request
     * @return
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public Result removeFna(ApiAppointmentRemoveFnaRequest request) {
        //校验预约信息是否存在
        Result<Appointment> result = checkAppointmentIsExist(request.getAppointmentBizId());
        Appointment appointment = result.getData();

        //预约解除关联FNA就是清空预约信息冗余的关联FNA业务id和关联FNA编号数据
        appointment.setFnaBizId("");
        appointment.setFnaNo("");
        iAppointmentService.saveOrUpdate(appointment);
        return Result.success();
    }

    /**
     * 预约编辑关联计划书
     *
     * @param request
     * @return
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public Result editProposal(ApiAppointmentEditProposalRequest request) {
        //校验预约信息是否存在
        Result<Appointment> result = checkAppointmentIsExist(request.getAppointmentBizId());
        Appointment appointment = result.getData();

        //修改预约信息表冗余的关联计划书业务id和关联计划书编号
        appointment.setProposalBizId(request.getProposalBizId());
        appointment.setProposalNo(request.getProposalNo());
        iAppointmentService.saveOrUpdate(appointment);
        return Result.success();
    }

    /**
     * 预约解除关联计划书
     *
     * @param request
     * @return
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public Result removeProposal(ApiAppointmentRemoveProposalRequest request) {
        //校验预约信息是否存在
        Result<Appointment> result = checkAppointmentIsExist(request.getAppointmentBizId());
        Appointment appointment = result.getData();

        //预约预约解除关联计划书就是清空预约信息冗余的关联计划书业务id和关联计划书编号
        appointment.setProposalBizId("");
        appointment.setProposalNo("");
        iAppointmentService.saveOrUpdate(appointment);
        return Result.success();
    }

    /**
     * 预约编辑转保声明
     *
     * @param request
     * @return
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public Result editPolicyTransfer(ApiPolicyTransferRequest request) {
        //校验预约信息是否存在
        Result<Appointment> result = checkAppointmentIsExist(request.getAppointmentBizId());
        Appointment appointment = result.getData();

        appointment.setPolicyTransfer(request.getPolicyTransfer());
        iAppointmentService.saveOrUpdate(appointment);
        return Result.success();
    }

    /**
     * 编辑预约状态
     * @param request
     * @return
     */
    @Override
    public Result editStatus(ApiAppointmentEditStatusRequest request) {
        //校验预约信息是否存在
        Result<Appointment> result = checkAppointmentIsExist(request.getAppointmentBizId());
        Appointment appointment = result.getData();
        if (1 == request.getOprType() || 2 == request.getOprType()) {
            appointment.setStatus(AppointmentStatusEnum.YQX.getItemValue());
        }
        iAppointmentService.saveOrUpdate(appointment);

        //取消预约-更新新单跟进状态为：取消预约
        if (2 == request.getOprType()) {
            //取消预约-更新新单跟进状态为取消预约
            editFollowStatus(request.getAppointmentBizId());
        }
        return Result.success();
    }

    /**
     * 取消预约-更新新单跟进状态为取消预约
     * @return
     */
    public Result editFollowStatus(String appointmentBizId) {
        List<PolicyFollow> followList = policyFollowService.queryListByAppointmentBizId(appointmentBizId);
        if (!CollectionUtils.isEmpty(followList)) {
            //更新当前预约ID绑定新单记录更新新单状态为取消预约。
            followList = followList.stream().map(dto -> {
                //取消预约
                dto.setStatus("QX_YY");
                return dto;
            }).collect(Collectors.toList());
            policyFollowService.saveOrUpdateBatch(followList);
        }
        return Result.success();
    }

    /**
     * 删除预约信息
     *
     * @param appointmentBizId
     * @return
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public Result del(String appointmentBizId) {
        //校验预约信息是否存在
        Result<Appointment> result = checkAppointmentIsExist(appointmentBizId);
        Appointment appointment = result.getData();
        iAppointmentService.del(appointmentBizId);
        return Result.success();
    }

    /**
     * 历史记录 - 签约信息
     * @param request
     * @return
     */
    @Override
    public Result<IPage<ApiAppointmentLogPageResponse>> logPage(ApiAppointmentLogPageRequest request) {
        Page<ApiAppointmentLogPageResponse> page = new Page<>(request.getPageNo(), request.getPageSize());
        IPage<ApiAppointmentLogPageResponse> iPage = iAppointmentService.logPage(page, request);
        return Result.success(iPage);
    }

    /**
     * 历史记录 - 签约信息 - 详情
     * @param appointmentLogBizId
     * @return
     */
    @Override
    public Result<ApiAppointmentLogDetailResponse> logDetail(String appointmentLogBizId) {
        ApiAppointmentLogDetailResponse response = null;
        AppointmentLog appointmentLog = iAppointmentLogService.queryOne(appointmentLogBizId);
        if (!Objects.isNull(appointmentLog)) {
            //预约信息日志表信息
            response = new ApiAppointmentLogDetailResponse();
            BeanUtils.copyProperties(appointmentLog,response);

            //预约-转介人信息日志列表
            List<AppointmentReferrerLog> referrerLogList = iAppointmentReferrerLogService.queryList(appointmentLogBizId);
            if (!CollectionUtils.isEmpty(referrerLogList)) {
                List<ApiAppointmentReferrerLogDto> referrerLogDtoList = referrerLogList.stream().map(dto -> {
                    ApiAppointmentReferrerLogDto logDto = new ApiAppointmentReferrerLogDto();
                    BeanUtils.copyProperties(dto,logDto);
                    return logDto;
                }).collect(Collectors.toList());
                response.setReferrerDtoList(referrerLogDtoList);
            }

            //预约-签单员信息日志列表
            List<AppointmentUserSignLog> userSignLogList = iAppointmentUserSignLogService.queryList(appointmentLogBizId);
            if (!CollectionUtils.isEmpty(userSignLogList)) {
                List<ApiAppointmentUserSignLogDto> userSignLogDtoList = referrerLogList.stream().map(dto -> {
                    ApiAppointmentUserSignLogDto logDto = new ApiAppointmentUserSignLogDto();
                    BeanUtils.copyProperties(dto,logDto);
                    return logDto;
                }).collect(Collectors.toList());
                response.setUserSignDtoList(userSignLogDtoList);
            }
        }
        return Result.success(response);
    }

    /**
     * 新增健康问卷和预约对象关系绑定
     *
     * @return
     */
    @Transactional(rollbackFor = Exception.class)
    public Result objectSaveJkQuestion(String appointmentBizId,
                                       ApiAnswerSaveRequest apiAnswerSaveRequest) {
//        if (Objects.isNull(apiAnswerSaveRequest)) {
//            throw new BusinessException("问卷-答题提交对象不能为空");
//        }
        ApiObjectSaveRequest apiObjectSaveRequest = new ApiObjectSaveRequest();
        apiObjectSaveRequest.setObjectBizId(appointmentBizId);
        apiObjectSaveRequest.setObjectName("预约");
        apiObjectSaveRequest.setObjectTableName("appointment");
        apiObjectSaveRequest.setQuestionnaireBizId("questionnaires_1001");
        apiQuestionnairesFeignClient.objectSave(apiObjectSaveRequest);
        //问卷-答题提交接口
        if (!Objects.isNull(apiAnswerSaveRequest)) {
            apiAnswerSaveRequest.setObjectBizId(appointmentBizId);
            apiAnswerSaveRequest.setQuestionnaireBizId("questionnaires_1001");
            apiQuestionnairesFeignClient.answerSave(apiAnswerSaveRequest);
        }
        return Result.success();
    }

    /**
     * 校验预约信息是否存在
     *
     * @param appointmentBizId
     * @return
     */
    public Result<Appointment> checkAppointmentIsExist(String appointmentBizId) {
        Appointment appointment = iAppointmentService.queryOne(appointmentBizId);
        if (Objects.isNull(appointment)) {
            //数据不存在
            throw new BusinessException(ResultCode.NULL_ERROR.getCode(), ResultCode.NULL_ERROR.getMessage());
        }
        return Result.success(appointment);
    }

}
