package com.prolog.upcloud.base.wh.operate.service;

import cn.hutool.core.date.DateTime;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.lang.Assert;
import cn.hutool.http.HttpRequest;
import cn.hutool.http.Method;
import com.alibaba.fastjson.JSONObject;
import com.prolog.framework.common.message.RestMessage;
import com.prolog.upcloud.base.wh.operate.dao.EisLogMapper;
import com.prolog.upcloud.base.wh.operate.model.EisLog;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.jdbc.datasource.DataSourceTransactionManager;
import org.springframework.stereotype.Component;
import org.springframework.transaction.TransactionDefinition;
import org.springframework.transaction.TransactionStatus;
import org.springframework.transaction.support.DefaultTransactionDefinition;

import javax.annotation.Resource;
import javax.validation.constraints.NotBlank;
import java.util.function.Consumer;
import java.util.function.Supplier;

import static cn.hutool.http.HttpRequest.post;
import static com.prolog.constant.EisInterfaceConstant.INTEGRATION_PREFIX;
import static com.prolog.upcloud.base.wh.operate.constant.EisConstant.*;

@Slf4j
@Component
public abstract class InterfacePlatform {

    @Resource
    private EisLogMapper eisLogMapper;
    @Resource
    private DataSourceTransactionManager transactionManager;

    @Value("${prolog.integration.url}")
    private String integrationUrl;

    public Object call4Eis(String url, String params) {

        String fullUrl = getUrl(url);

        EisLog eisLog = warpEisLog(params, fullUrl);

        saveResult(eisLog, (EisLog log) -> getEisResponse(log, () -> invokeInterfacePlatform(params, fullUrl, Method.POST)));

        return eisLog;
    }

    public RestMessage call(String url, String params) {

        String fullUrl = getUrl(url);

        return invokeInterfacePlatform(params, fullUrl, Method.POST);
    }

    private String getUrl(@NotBlank String url) {
        return integrationUrl + INTEGRATION_PREFIX + url;
    }

    /**
     * 初始化日志
     */
    private EisLog warpEisLog(String request, String url) {
        DateTime now = DateUtil.date();
        EisLog log = new EisLog();
        log.setRequest(request);
        log.setGmtCreate(now);
        log.setGmtModified(now);
        log.setInitiator(INITIATOR_WMS);
        log.setStatus(INIT);
        log.setUrl(url);
        return log;
    }

    private void saveResult(EisLog eisLog, Consumer<EisLog> consumer) {
        try {
            consumer.accept(eisLog);
            saveEisLog(eisLog, null);
        } catch (Exception e) {
            log.error("", e);
            saveEisLog(eisLog, e);
        }
    }

    private void saveEisLog(EisLog eisLog, Exception e) {
        eisLog.setStatus(SUCCESS);
        if (e != null) {
            eisLog.setStatus(FAIL);
            eisLog.setResponse(e.getMessage());
        }
        eisLog.setGmtModified(DateUtil.date());
        saveLog(eisLog);
    }

    private void getEisResponse(EisLog eisLog, Supplier<RestMessage> supplier) {

        RestMessage msg = supplier.get();

        String response = JSONObject.toJSONString(msg);
        log.info("eis.response:{}", response);
        Assert.notNull(msg, "调用EIS服务返回异常");
        Assert.isTrue(msg.isSuccess(), msg.getMessage());

        eisLog.setGmtModified(DateUtil.date());
        eisLog.setResponse(response);
        eisLog.setStatus(SUCCESS);
    }

    private void saveLog(EisLog eisLog) {
        TransactionStatus ts = getTransactionStatus(TransactionDefinition.PROPAGATION_REQUIRES_NEW);
        try {
            eisLogMapper.save(eisLog);
        } catch (Exception e) {
            log.error("", e);
            eisLog.setResponse(e.getMessage());
            eisLogMapper.save(eisLog);
        }
        transactionManager.commit(ts);
    }

    private TransactionStatus getTransactionStatus(int propagation) {
        DefaultTransactionDefinition def = new DefaultTransactionDefinition();
        def.setPropagationBehavior(propagation); // 事物隔离级别，开启新事务.
        return transactionManager.getTransaction(def); // 获得事务状态
    }

    /**
     * 拼装请求地址
     */
    private RestMessage invokeInterfacePlatform(@NotBlank String params, @NotBlank String url, Method method) {
        HttpRequest request;
        if (method == Method.POST) {
            request = post(url);
        } else {
            request = new HttpRequest(url);
        }
        return JSONObject.parseObject(request.body(params).execute().body(), RestMessage.class);
    }

}
