package cn.quant.baa.pay.acquirer;

import cn.quant.baa.pay.jpa.entity.TransactionSummaryEntity;
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 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 final void register(Acquirer acquirer) {
        acquirers.put(acquirer.code(), acquirer);
    }

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

    @Override
    public ChannelResponse pay(PayRequestData request, TransactionSummaryEntity transaction) throws Exception {
        ChannelResponse response = acquirers.get(request.getChanId()).pay(request, transaction);
        response.setOrderNo(String.valueOf(transaction.getTransactionId()));
        return response;
    }

    @Override
    public ChannelResponse refund(RefundRequestData request) throws Exception {
        return acquirers.get(request.getChanId()).refund(request);
    }

    @Override
    public ChannelResponse checkPay(CheckPayRequestData request) throws Exception {
        return acquirers.get(request.getChanId()).checkPay(request);
    }

    @Override
    public ChannelResponse checkRefund(CheckRefundRequestData request) throws Exception {
        return acquirers.get(request.getChanId()).checkRefund(request);
    }

    @Override
    public ChannelResponse close(CloseRequestData request) throws Exception {
        return acquirers.get(request.getChanId()).close(request);
    }
}
