package cn.quant.baa.pay.acquirer;

import cn.quant.baa.pay.jpa.entity.PayHistoryEntity;
import cn.quant.baa.pay.model.web.*;
import cn.quant.spring.NotSupportedException;
import cn.quant.spring.security.Base64Cipher;
import cn.quant.spring.security.CharacterCipher;
import cn.quant.spring.util.RandomSequencer;
import com.fasterxml.jackson.databind.JsonNode;

import javax.crypto.Cipher;
import javax.crypto.spec.GCMParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import java.nio.charset.Charset;
import java.util.HashMap;
import java.util.Map;

/**
 * Created by Administrator on 2021/8/31 0031.
 */
public class MerchantAcquirer implements Acquirer {

    private final static MerchantAcquirer instance = new MerchantAcquirer();

    private final static Map<Object, Acquirer> acquirers = new HashMap<>();

    protected Cipher cipher;

    protected SecretKeySpec secretKey;

    protected CharacterCipher secretCipher;

    protected AcquirerProperties properties;

    protected MerchantAcquirer() {
    }

    public static MerchantAcquirer getInstance() {
        return instance;
    }

    public MerchantAcquirer init(AcquirerProperties properties) throws Exception {

        this.secretCipher = new Base64Cipher();
        String secretType = properties.getSecretType();
        if (secretType.startsWith("AES")) {
            this.secretKey = new SecretKeySpec(properties.getSecretKey().getBytes(Charset.forName("utf-8")), "AES");
        }
        this.cipher = Cipher.getInstance(secretType);
        GCMParameterSpec spec = new GCMParameterSpec(128, RandomSequencer.randomNumber().getBytes(Charset.forName("utf-8")));
        this.cipher.init(Cipher.DECRYPT_MODE, this.secretKey, spec);

        this.properties = properties;

        return this;
    }

    public void register(Acquirer acquirer) {
        acquirers.put(acquirer.code(), acquirer);
    }

    @Override
    public Object code() {
        throw new NotSupportedException();
    }

    @Override
    public JsonNode pay(PayRequestData payRequestData, PayHistoryEntity payHistoryEntity) {
        return acquirers.get(payRequestData.getChanId()).pay(payRequestData, payHistoryEntity);
    }

    @Override
    public JsonNode refund(RefundRequestData refundRequestData) {
        return acquirers.get(refundRequestData.getChanId()).refund(refundRequestData);
    }

    @Override
    public JsonNode checkPay(CheckPayRequestData checkPayRequestData) {
        return acquirers.get(checkPayRequestData.getChanId()).checkPay(checkPayRequestData);
    }

    @Override
    public JsonNode checkRefund(CheckRefundRequestData checkRefundRequestData) {
        return acquirers.get(checkRefundRequestData.getChanId()).checkRefund(checkRefundRequestData);
    }

    @Override
    public JsonNode close(CloseRequestData closeRequestData) {
        return acquirers.get(closeRequestData.getChanId()).close(closeRequestData);
    }
}
