package com.bohuikeji.delivery.backstage.service.impl;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.bohuikeji.delivery.backstage.entity.TCourier;
import com.bohuikeji.delivery.backstage.entity.TCourierSaveDetail;
import com.bohuikeji.delivery.backstage.mapper.TCourierSaveDetailMapper;
import com.bohuikeji.delivery.backstage.service.ITCourierSaveDetailService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.bohuikeji.delivery.backstage.service.ITCourierService;
import com.bohuikeji.delivery.backstage.service.ITCourierWithdrawService;
import com.bohuikeji.delivery.backstage.task.CourierSaveTask;
import com.bohuikeji.frame.module.admin.base.ServiceImplBase;
import com.bohuikeji.frame.module.admin.task.TaskDelayed;
import com.bohuikeji.frame.module.admin.task.TaskQueue;
import com.bohuikeji.frame.module.admin.component.StaticComponent;
import com.bohuikeji.frame.module.admin.entity.back.DataPage;
import com.bohuikeji.frame.module.admin.utils.Constants;
import com.bohuikeji.frame.module.admin.utils.StringUtils;
import com.bohuikeji.frame.module.admin.utils.TaskUtils;
import jodd.http.HttpRequest;
import jodd.http.HttpResponse;
import jodd.net.MimeTypes;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.http.MediaType;
import org.springframework.stereotype.Service;

import java.math.BigDecimal;
import java.net.MalformedURLException;
import java.net.URL;
import java.time.Duration;
import java.time.LocalDate;
import java.time.LocalDateTime;

import static com.bohuikeji.delivery.backstage.task.CourierSaveTask.PAY_TIME_OUT;

/**
 * <p>
 * 骑手保险记录表 服务实现类
 * </p>
 *
 * @author 10552
 * @since 2021-05-14
 */
@Slf4j
@Service
@RequiredArgsConstructor
public class TCourierSaveDetailServiceImpl extends ServiceImplBase<TCourierSaveDetailMapper, TCourierSaveDetail> implements ITCourierSaveDetailService {
    final ITCourierService courierService;
    final ITCourierWithdrawService withdrawService;
    final TCourierSaveDetailMapper cardMapper;
    final CourierSaveTask courierSaveTask;


    /**
     * 判断骑手是否今日已经投保
     *
     * @param courierId 骑手ID
     * @return 已投ture，未投false
     */
    @Override
    public boolean isInsure(Integer courierId) {
        if ("全职".equals(courierService.getById(courierId).getCourierType())){
            return true;
        }
        TCourierSaveDetail saveDetail=getOne(new QueryWrapper<TCourierSaveDetail>().eq("courier_id",courierId).eq("insured_date", LocalDate.now()).in("status","投保成功","等待支付"),false);
        if (saveDetail==null){
            return false;
        }
        if("投保成功".equals(saveDetail.getStatus())){
            return true;
        }
        /*if ("等待支付".equals(saveDetail.getStatus())){
            //如果有待支付的保单再核查一遍保单状态
            JSONObject result= TCourierSaveDetailServiceImpl.checkInsure(saveDetail.getProposalNo());
            if (result!=null){
                insureSuccess(saveDetail,result);
                return true;
            }
            //如果已经超时，则处置
            Duration duration=Duration.between(saveDetail.getGmtCreate(), LocalDateTime.now());
            if (duration.toMinutes()>=PAY_TIME_OUT) {
                saveDetail.setStatus("支付超时");
                updateById(saveDetail);
            }
        }*/
        return false;
    }

    /**
     * 投保
     *
     * @param courierId 骑手ID
     * @return 投保成功返回支付地址，投保失败返回null
     */
    @Override
    public String insure(Integer courierId) {
        TCourier courier=courierService.getById(courierId);
        JSONObject req=new JSONObject();
        req.put("productCode","MP03011088");
        //req.put("appKey","670c45dd00e1f185f7efc9cbf7d72688");测试环境
        req.put("appKey","6c1af29bf7c64503fea991a3dc8d7b79");
        req.put("oper_type","A");
        req.put("returnUrl", Constants.BX_END_H5);
        req.put("frontNotifyUrl",StaticComponent.TOOLS_EVN_URL+"/delivery/api/courier/save/notice/url");
        JSONObject contract = new JSONObject();
        JSONArray applicantInfoList=new JSONArray(1);
        applicantInfoList.add(getInfo(courier.getCourierCard(),courier.getCourierName(),courier.getCourierPhone()));
        contract.put("applicantInfoList",applicantInfoList);
        JSONArray insurantInfoList=new JSONArray(1);
        insurantInfoList.add(getInfo(courier.getCourierCard(),courier.getCourierName(),courier.getCourierPhone()));
        contract.put("insurantInfoList",insurantInfoList);
        JSONObject baseInfo=new JSONObject();
        baseInfo.put("insuranceEndDate",LocalDate.now().format(StringUtils.dataFormat)+" 23:59:59");
        baseInfo.put("insuranceBeginDate", LocalDateTime.now().plusSeconds(30).format(StringUtils.dataTimeFormat));
        contract.put("baseInfo",baseInfo);
        req.put("contract",contract);
        log.info(req.toJSONString());
        String res= HttpRequest.post(StaticComponent.BX_API_TB).bodyText(req.toJSONString(), MimeTypes.MIME_APPLICATION_JSON,"UTF-8")
                .send()
                .contentType("application/json","utf-8").bodyText();
        log.info("投保返回{}",res);
        if (StringUtils.isNotBlank(res)){
            JSONObject resJson= JSON.parseObject(res);
            if (resJson!=null){
                if(200==resJson.getIntValue("code")){
                    JSONObject data=JSON.parseObject(resJson.getString("data"));
                    //订单号
                    TCourierSaveDetail saveDetail=initSaveDetail(courier,data.getJSONObject("policyInfo").getString("orderNo"));
                    //通知单号
                    saveDetail.setNoticeNo(data.getJSONObject("policyInfo").getString("thirdBatchNo"));
                    //投保单号
                    saveDetail.setProposalNo(data.getJSONObject("policyInfo").getString("proposalNo"));
                    //支付地址放入
                    saveDetail.setPayUrl(getRealPayUrl(data.getString("payUrl")));
                    save(saveDetail);
                    //延迟10秒放入队列
                    TaskUtils.add(courierSaveTask).addParam(CourierSaveTask.KEY_NO,data.getJSONObject("policyInfo").getString("proposalNo"));
                    return saveDetail.getPayUrl();
                }
                else{
                    log.error("投保失败，保险返回：{}",res);
                    throw new RuntimeException(resJson.getString("msg"));
                }
            }
        }
        log.error("投保失败，保险返回：{}",res);
        throw new RuntimeException("投保失败，请勿重复投保");
    }

    /**
     * 查询今日投保详情
     *
     * @param courierId 骑手ID
     * @return 如果未投保或未支付返回null,
     */
    @Override
    public TCourierSaveDetail getInsurance(Integer courierId) {
        return  getOne(new QueryWrapper<TCourierSaveDetail>().eq("courier_id",courierId).eq("insured_date", LocalDate.now()).in("status","投保成功","等待支付"),false);
    }

    /**
     * 分页查询我的投保记录
     *
     * @param courierId 骑手ID
     * @param page      分页查询条件
     * @return 返回
     */
    @Override
    public IPage<TCourierSaveDetail> pageInsurance(Integer courierId, DataPage<TCourierSaveDetail> page) {
        return page(page,new QueryWrapper<TCourierSaveDetail>().eq("courier_id",courierId));
    }

    /**
     * 投保支付成功处理
     * @param saveDetail 需要更新的待支付保单
     * @param policyInfo 保单核查接口返回的结果
     * @return
     */
    @Override
    public TCourierSaveDetail insureSuccess(TCourierSaveDetail saveDetail,JSONObject policyInfo) {
        saveDetail.setPdfUrl(policyInfo.getString("epolicy"));
        saveDetail.setInsuredNumber(policyInfo.getString("policyNo"));
        saveDetail.setCourierPayChannel("平安保险");
        saveDetail.setStatus("投保成功");
        saveDetail.setInsuredPremium(new BigDecimal("5.00"));
        updateById(saveDetail);
        //直接发放补贴金额
        withdrawService.sendToAliPay("发放保险补贴金",new BigDecimal("3.00"),saveDetail.getCourierId());
        return saveDetail;
    }

    /**
     * 查询保单信息
     * @param orderNum 订单号
     * @return
     */
    public static String queryPlatform(String orderNum){
        JSONObject reqBody=new JSONObject();
        reqBody.put("orderNo",orderNum);
        log.info("查询保单接口地址：{}",StaticComponent.BX_API_CX);
        log.info("查询保单参数：{}",reqBody.toJSONString());
        String res=HttpRequest.post(StaticComponent.BX_API_CX)
                .bodyText(reqBody.toJSONString(), MediaType.APPLICATION_JSON_VALUE,"UTF-8")
                .send().contentType(MediaType.APPLICATION_JSON_VALUE,"utf-8").bodyText();
        log.info("查询保单返回：{}",res);
        return res;
    }

    /**
     * 向平安保险系统核查保单状态，成返回保单信息，返回失败返回null
     * @param proposalNo 投保单号
     * @return
     */
    static public JSONObject checkInsure(String proposalNo){
        JSONObject reqJson=new JSONObject();
        reqJson.put("productCode","MP03011088");
        reqJson.put("appKey","6c1af29bf7c64503fea991a3dc8d7b79");
        reqJson.put("oper_type","CB");
        reqJson.put("appPolicyNo",proposalNo);
        String res=HttpRequest.post("http://t.c.tdbxjj.com/api/pip-core-engine/issuing/TB101003").bodyText(reqJson.toJSONString(), MimeTypes.MIME_APPLICATION_JSON,"UTF-8").send()
                .contentType("application/json","utf-8").bodyText();
        log.info("核查保单返回：{}",res);
        if (StringUtils.isNotBlank(res)){
            JSONObject resJson= JSON.parseObject(res);
            if (resJson!=null){
                if(200==resJson.getIntValue("code")){
                    JSONObject data=JSON.parseObject(resJson.getString("data"));
                    if (data!=null){
                        JSONObject policyInfo=data.getJSONObject("policyInfo");
                        if (policyInfo!=null){
                            return policyInfo;
                        }
                    }
                }
            }
        }
        return null;
    }

    /**
     * 初始化保险用户信息
     * @param certificateNo 身份证号码
     * @param name 姓名
     * @param phone 电话
     * @return
     */
    public static JSONObject getInfo(String certificateNo,String name,String phone){
        JSONObject json=new JSONObject();
        json.put("name", name);
        json.put("mobileTelephone",phone);
        json.put("certificateNo",certificateNo);
        return json;
    }

    /**
     * 初始化投保信息
     * @param courier 投保骑手
     * @param orderNo 支付单号
     * @return
     */
    public TCourierSaveDetail initSaveDetail(TCourier courier,String orderNo){
        TCourierSaveDetail saveDetail=new TCourierSaveDetail();
        saveDetail.setCourierId(courier.getCourierId());
        saveDetail.setCourierCard(courier.getCourierCard());
        saveDetail.setCourierName(courier.getCourierName());
        saveDetail.setCourierPayNumber(orderNo);
        saveDetail.setInsuredDate(LocalDate.now());
        saveDetail.setStatus("等待支付");
        return saveDetail;
    }

    /**
     * 获取真实支付地址
     * 由于平安返回的支付地址只能使用一次，该方法对其进行模拟浏览器重定向，直到得到真实地址后返回
     * @param url 平安投保返回的支付地址
     * @return
     */
    public static String getRealPayUrl(String url){
        while (true){
            HttpResponse response=HttpRequest.get(url).host(getHost(url)).send();
            if (response.statusCode()==301||response.statusCode()==302){
                url=response.header("Location");
                response=HttpRequest.get(url).cookies(response.cookies()).host(getHost(url)).send();
                continue;
            }
            break;
        }
        return url;
    }

    /**
     * 解析HOST
     * @param url
     * @return
     */
    private static String getHost(String url){
        try {
            return new URL(url).getHost();
        } catch (MalformedURLException e) {
            return "www.pingan.com";
        }
    }
}
