package cn.quant.baa.pay.rest;

import cn.quant.baa.pay.acquirer.AcquirerProperties;
import cn.quant.baa.pay.acquirer.AcquirerPropertiesSource;
import cn.quant.baa.pay.acquirer.ChannelRequest;
import cn.quant.baa.pay.acquirer.ChannelResponse;
import cn.quant.baa.pay.context.TransactionSession;
import cn.quant.baa.pay.model.web.PayResponseData;
import cn.quant.baa.pay.util.AssertUtils;
import cn.quant.spring.NullException;
import cn.quant.spring.ProfileException;
import cn.quant.spring.http.HttpResponseData;
import cn.quant.spring.rest.AbstractController;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.SerializationFeature;
import com.fasterxml.jackson.databind.module.SimpleModule;
import com.fasterxml.jackson.databind.ser.std.ToStringSerializer;
import com.fasterxml.jackson.datatype.jsr310.deser.LocalDateDeserializer;
import com.fasterxml.jackson.datatype.jsr310.deser.LocalDateTimeDeserializer;
import com.fasterxml.jackson.datatype.jsr310.ser.LocalDateSerializer;
import com.fasterxml.jackson.datatype.jsr310.ser.LocalDateTimeSerializer;
import com.fasterxml.jackson.datatype.jsr310.ser.ZonedDateTimeSerializer;
import org.springframework.beans.factory.annotation.Autowired;

import java.io.IOException;
import java.text.SimpleDateFormat;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.ZonedDateTime;
import java.util.Map;

import static cn.quant.baa.pay.dict.MessageEnum.ACQUIRER_NOSUCH;
import static cn.quant.baa.pay.dict.MessageEnum.ILLEGAL_REQ_CHAN_ID;
import static cn.quant.baa.pay.dict.MessageEnum.ILLEGAL_REQ_DATA;

/**
 * Created by Administrator on 2021/8/28 0028.
 */
public abstract class BusinessController extends AbstractController {

    protected final static ObjectMapper objectMapper = new ObjectMapper();

    @Autowired
    private AcquirerPropertiesSource acquirerPropertiesSource;

    public AcquirerProperties check(ChannelRequest data) {
        if (data == null) {
            AssertUtils.throwMessage(ILLEGAL_REQ_DATA);
        }
        String chanId = data.getChanId();
        if (chanId == null) {
            AssertUtils.throwMessage(ILLEGAL_REQ_CHAN_ID, chanId);
        }

        AcquirerProperties properties = acquirerPropertiesSource.get(Long.valueOf(chanId));
        if (properties == null) {
            throw new NullException("Acquirer not found : {}; {};", chanId, data);
        }

        return properties;
    }

    public BusinessController() {
        SimpleModule simpleModule = new SimpleModule();
        simpleModule.addSerializer(Long.class, ToStringSerializer.instance);
        simpleModule.addSerializer(Long.TYPE, ToStringSerializer.instance);
        simpleModule.addSerializer(LocalDateTime.class, LocalDateTimeSerializer.INSTANCE);
        simpleModule.addDeserializer(LocalDateTime.class, LocalDateTimeDeserializer.INSTANCE);
        simpleModule.addSerializer(LocalDate.class, LocalDateSerializer.INSTANCE);
        simpleModule.addDeserializer(LocalDate.class, LocalDateDeserializer.INSTANCE);
        simpleModule.addSerializer(ZonedDateTime.class, ZonedDateTimeSerializer.INSTANCE);
        objectMapper.registerModule(simpleModule);
        objectMapper.setDateFormat(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"));
        objectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
        objectMapper.configure(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS, false);
    }

    public Map deserialize(String value) throws IOException {
        return objectMapper.readValue(value.getBytes(), Map.class);
    }

    public String serialize(Object value) throws JsonProcessingException {
        return objectMapper.writeValueAsString(value);
    }

    public HttpResponseData response(ChannelResponse response) {
        TransactionSession session = TransactionSession.session();
        PayResponseData data = new PayResponseData();
        data.setOrderNo(response.getOrderNo());
        data.setPrepay(response.getNotification());

        HttpResponseData responseData = new HttpResponseData(data);
        responseData.setSuccess(response.getSuccess());
        responseData.setMessage(response.getMessage());
        responseData.setStatus(response.getCode());
        responseData.setRequestId(session.getRequestId());
        return responseData;
    }
}
