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

import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
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.ApiAppointmentAddResponse;
import com.yd.csf.feign.response.appointment.ApiAppointmentDetailResponse;
import com.yd.csf.feign.response.appointment.ApiAppointmentPageResponse;
import com.yd.csf.service.dto.PolicySigner;
import com.yd.csf.service.enums.AppointmentStatusEnum;
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.question.feign.client.ApiQuestionnairesFeignClient;
import com.yd.question.feign.dto.ApiAnswerSessionsDto;
import com.yd.question.feign.request.ApiAnswerSaveRequest;
import com.yd.question.feign.request.ApiBatchSaveAnswerRequest;
import com.yd.question.feign.request.ApiObjectSaveRequest;
import com.yd.question.feign.response.ApiAnswerSaveResponse;
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 javax.annotation.Resource;
import java.time.ZoneId;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Objects;

/**
 * 预约信息业务实现类
 */
@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 ApiQuestionnairesFeignClient apiQuestionnairesFeignClient;

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

    /**
     * 预约分页查询
     *
     * @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);
        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());
        //受益人列表信息
        Result<List<ApiBeneficiaryInfoDto>> result4 = apiBeneficiaryService.list(appointmentBizId);
        response.setApiBeneficiaryInfoDtoList(result4.getData());
        //第二持有人信息
        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) {
        //新增预约入参字段校验（非库校验）
        apiAppointmentCheckService.checkAddRequest(request);

        //新增预约-添加预约信息主表数据 - 预约状态为待预约
        Result<Appointment> appointmentResult = addAppointmentData(request.getApiAppointmentInfoDto(), AppointmentStatusEnum.DYY.getItemValue());
        Appointment appointment = appointmentResult.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.getApiBeneficiaryInfoDtoList(), appointment.getAppointmentBizId());

        //添加第二持有人信息表数据
        apiSecondHolderService.addSecondHolderData(request.getApiSecondHolderInfoDto(), appointment.getAppointmentBizId());

        //新增健康问卷和预约对象关系绑定
        objectSaveJkQuestion(appointment.getAppointmentBizId());

        //预约编号和预约业务id更新到FNA表（提交待预约状态，预约信息的预约业务id和预约编号更新到Fna表的预约业务id和预约编号）
        updateFnaBizIdAndNo(appointment.getFnaBizId(), appointment.getAppointmentBizId(), appointment.getAppointmentNo());
        ApiAppointmentAddResponse response = new ApiAppointmentAddResponse();
        response.setAppointmentBizId(appointment.getAppointmentBizId());
        return Result.success(response);
    }

    /**
     * 提交待预约状态，预约信息更新到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());
        }
        //校验预约信息-客户和fna入参
        apiAppointmentCheckService.checkCustomerAndFna(request.getApiAppointmentInfoDto(), "预约信息-");

        //新增预约暂存-添加预约信息主表数据为暂存状态
        Result<Appointment> appointmentResult = addAppointmentData(request.getApiAppointmentInfoDto(), AppointmentStatusEnum.ZC.getItemValue());
        Appointment appointment = appointmentResult.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.getApiBeneficiaryInfoDtoList(), appointment.getAppointmentBizId());

        //添加第二持有人信息表数据
        apiSecondHolderService.addSecondHolderData(request.getApiSecondHolderInfoDto(), appointment.getAppointmentBizId());

        //预约编号和预约业务id更新到FNA表（提交待预约状态，预约信息的预约业务id和预约编号更新到Fna表的预约业务id和预约编号）
        updateFnaBizIdAndNo(appointment.getFnaBizId(), appointment.getAppointmentBizId(), appointment.getAppointmentNo());

        //新增健康问卷和预约对象关系绑定
        objectSaveJkQuestion(appointment.getAppointmentBizId());

        return Result.success();
    }

    /**
     * 新增预约-添加预约信息主表数据
     *
     * @param dto
     * @return
     */
    @Transactional(rollbackFor = Exception.class)
    public Result<Appointment> addAppointmentData(ApiAppointmentInfoDto dto, Integer status) {
        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());
        iAppointmentService.saveOrUpdate(appointment);
        return Result.success(appointment);
    }

    /**
     * 编辑预约提交 (聚合信息编辑预约提交)
     *
     * @param request
     * @return
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public Result edit(ApiAppointmentEditRequest request) {
        //编辑预约入参字段校验（非库校验）
        apiAppointmentCheckService.checkEditRequest(request);

        Integer status = null;
        Appointment appointmentCheck = null;
        if (!Objects.isNull(request.getApiAppointmentInfoDto())) {
            //校验预约信息是否存在
            Result<Appointment> result = checkAppointmentIsExist(request.getApiAppointmentInfoDto().getAppointmentBizId());
            appointmentCheck = result.getData();
            if (AppointmentStatusEnum.ZC.getItemValue().equals(appointmentCheck.getStatus())) {
                //当前为暂存状态——>提交更新为待预约状态
                status = AppointmentStatusEnum.DYY.getItemValue();
            }
//            else if (AppointmentStatusEnum.DYY.getItemValue().equals(appointmentCheck.getStatus())){
//                if (Objects.isNull(request.getApiAppointmentInfoDto().getConfirmAppointmentTime())) {
//                    //待预约提交到待签署状态，确定预约时间不能为空
//                    throw new BusinessException("待预约提交确定预约时间不能为空!");
//                }
//                //当前为待预约状态——>提交更新为待签署状态-->到新单跟进
//                status = AppointmentStatusEnum.DQS.getItemValue();
//            }
            //其他状态下都是单纯编辑数据不做状态流转更新
        }

        //编辑预约提交-编辑预约信息主表数据
        Result<Appointment> appointmentResult = editAppointmentData(request.getApiAppointmentInfoDto(), status);
        Appointment appointment = appointmentResult.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.getApiBeneficiaryInfoDtoList(), appointment.getAppointmentBizId());

        //编辑第二持有人信息表数据
        apiSecondHolderService.editSecondHolderData(request.getApiSecondHolderInfoDto(), appointment.getAppointmentBizId());

        if (!Objects.isNull(status) && AppointmentStatusEnum.DYY.getItemValue().equals(status)) {
            //当前为暂存状态——>提交更新为待预约状态需要更新Fna表的编号和业务id完成绑定关联
            //预约编号和预约业务id更新到FNA表（提交待预约状态，预约信息的预约业务id和预约编号更新到Fna表的预约业务id和预约编号）
            updateFnaBizIdAndNo(appointment.getFnaBizId(), appointment.getAppointmentBizId(), appointment.getAppointmentNo());
        }

        //远程调用-问卷-答题提交接口
        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;
        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.getApiBeneficiaryInfoDtoList();
            // 第二持有人
            apiSecondHolderInfoDto = response.getApiSecondHolderInfoDto();
        }
        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.setAppointmentBizId(appointment.getAppointmentBizId());
        follow.setAppointmentNo(appointment.getAppointmentNo());
        //客户信息表唯一业务ID
        follow.setCustomerBizId(appointment.getCustomerBizId());
        if (customer != null) {
            //客户名称
            follow.setCustomerName(customer.getFirstNamePinyin());
        }
        //待跟进
        follow.setStatus(PolicyFollowStatusEnum.FOLLOW_UP.getItemValue());
        follow.setNextStatusList(policyFollowService.getNextStatus(PolicyFollowStatusEnum.FOLLOW_UP));
        //TODO 保险公司业务id
//        follow.setInsurerBizId();
        //TODO 期交保费
//        follow.setPaymentPremium();
        // 保單持有人
        if (apiPolicyholderInfoDto != null) {
            follow.setPolicyHolder(apiPolicyholderInfoDto.getName());
        }
        //TODO 预缴年期
//        follow.setPrepaidTerm();
        //TODO 产品类别
//        follow.setProductCate();
        //TODO 对账公司
//        follow.setReconciliationCompany();
        //TODO 对账公司业务id
//        follow.setReconciliationCompanyBizId();
        //TODO 续保日期
//        follow.setRenewalDate();
        // 用户业务员id
        follow.setUserBizId(appointment.getCreatorId());
        if (!Objects.isNull(apiInsurantInfoDto)) {
            // 受保人
            follow.setInsured(apiInsurantInfoDto.getName());
            // 受保人与保單持有人关系
            if ("MYSELF".equals(apiInsurantInfoDto.getPolicyholderRel())) {
                follow.setInsured(follow.getPolicyHolder());
            }
        }

        if (!Objects.isNull(apiProductPlanMainInfoDto)) {
            //币种
            follow.setCurrency(apiProductPlanMainInfoDto.getCurrency());
            //生效日期
            if (!Objects.isNull(apiProductPlanMainInfoDto.getPolicyEffectiveDate())) {
                follow.setEffectiveDate(Date.from(apiProductPlanMainInfoDto.getPolicyEffectiveDate().atZone(ZoneId.systemDefault()).toInstant()));
            }
            //首期保费（不含徽费，预缴保费）每期保费
            follow.setInitialPremium(apiProductPlanMainInfoDto.getEachIssuePremium());
            //保险公司
            follow.setInsurer(apiProductPlanMainInfoDto.getCompanyName());
            //是否预缴
            follow.setIsPrepaid(apiProductPlanMainInfoDto.getIsPrepay());
            //供款年期
            if (StringUtils.isNotBlank(apiProductPlanMainInfoDto.getPaymentTerm())) {
                follow.setPaymentTerm(Integer.getInteger(apiProductPlanMainInfoDto.getPaymentTerm()));
                if (follow.getPaymentTerm() == null) {
                    follow.setPaymentTerm(productPlan.getPaymentTerm());
                }
            }
            //产品名称
            follow.setProductName(apiProductPlanMainInfoDto.getProductName());
            //签单员列表
            setSignerList(follow, appointment);
        }

        policyFollowService.saveOrUpdate(follow);

        // 同步保存保单（产品计划）
        savePolicy(productPlan, apiPolicyholderInfoDto, apiInsurantInfoDto, apiProductPlanMainInfoDto, policyBizId, policyTransfer);
        // 同步保存保单产品计划附加险
        savePolicyAdditional(apiProductPlanAdditionalInfoDtoList, policyBizId);
        // 同步保存保单投保人
        savePolicyPolicyholder(apiPolicyholderInfoDto, policyBizId);
        // 同步保存保单受保人
        savePolicyInsurant(apiInsurantInfoDto, policyBizId);
        // 同步保存保单受益人
        savePolicyBeneficiary(apiBeneficiaryInfoDtoList, policyBizId);
        // 同步保存保单第二持有人
        savePolicySecondHolder(apiSecondHolderInfoDto, policyBizId);
        // 同步问卷信息
        savePolicyQuestionnaire(appointment.getAppointmentBizId(), policyBizId);

        return Result.success();
    }

    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);
        follow.setSignerList(GSONUtil.toJson(signerList));
    }

    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.getName());

        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.getName());

        return policyPolicyholderService.saveOrUpdate(policyPolicyholder);
    }

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

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

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

        //编辑预约-编辑预约信息主表数据
        editAppointmentData(apiAppointmentInfoDto, null);
        return Result.success();
    }

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

        BeanUtils.copyProperties(dto, appointment);
        if (!Objects.isNull(status)) {
            //不为空设置状态
            appointment.setStatus(status);
        }
        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 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();
    }

    /**
     * 新增健康问卷和预约对象关系绑定
     *
     * @return
     */
    @Transactional(rollbackFor = Exception.class)
    public Result objectSaveJkQuestion(String appointmentBizId) {
        ApiObjectSaveRequest apiObjectSaveRequest = new ApiObjectSaveRequest();
        apiObjectSaveRequest.setObjectBizId(appointmentBizId);
        apiObjectSaveRequest.setObjectName("预约");
        apiObjectSaveRequest.setObjectTableName("appointment");
        apiObjectSaveRequest.setQuestionnaireBizId("questionnaires_1001");
        apiQuestionnairesFeignClient.objectSave(apiObjectSaveRequest);
        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);
    }

}
