package com.sunyard.chsm.sdf.adapter;

import com.sun.jna.ptr.PointerByReference;
import com.sunyard.chsm.sdf.context.AlgId;
import com.sunyard.chsm.sdf.context.SdrCode;
import com.sunyard.chsm.sdf.context.SunyardAlgId;
import com.sunyard.chsm.sdf.lib.SdfLibrary;
import com.sunyard.chsm.sdf.lib.SunyardSdfLibrary;
import lombok.extern.slf4j.Slf4j;
import org.springframework.util.ClassUtils;

import java.lang.reflect.Proxy;
import java.util.Objects;
import java.util.UUID;

/**
 * @author liulu
 * @since 2024/11/4
 */
@Slf4j
public class SunyardJnaSdfAdaptor extends JnaSdfAdaptor {

    private final String ip;
    private final Integer port;
    private final Integer connTimeout;
    private final Integer dealTimeout;

    public SunyardJnaSdfAdaptor(String ip, int port) {
        this(ip, port, 3000, 3000);
    }

    public SunyardJnaSdfAdaptor(String ip, int port, int connTimeout, int dealTimeout) {
        super((SdfLibrary) Proxy.newProxyInstance(ClassUtils.getDefaultClassLoader(),
                new Class[]{SdfLibrary.class},
                (proxy, method, args) -> {
                    Object res = method.invoke(SunyardSdfLibrary.INSTANCE, args);
                    if (!(res instanceof Integer)) {
                        return res;
                    }
                    int resInt = (Integer) res;
                    if (Objects.equals("SDF_ExternalVerify_ECC", method.getName())) {
                        log.info("SDF_ExternalVerify_ECC: {}, 返回值: {}", method.getName(), Integer.toHexString(resInt));
                        return resInt;
                    }
                    if (method.getName().startsWith("SDF_")) {
                        if (resInt != SdrCode.SDR_OK.getCode()) {
                            log.warn("调用异常: {}, 返回值: {} -{}", method.getName(), Integer.toHexString(resInt), resInt);
                            SdrCode sdrCode = SdrCode.of((Integer) res);
                            throw new IllegalArgumentException(sdrCode != null ? sdrCode.getMsg() : "调用sdf接口异常: " + Integer.toHexString(resInt));
                        }
                    }
                    return res;
                }
        ));
        this.ip = ip;
        this.port = port;
        this.connTimeout = connTimeout;
        this.dealTimeout = dealTimeout;
    }

    @Override
    public String openDevice() {
        PointerByReference phDeviceHandle = new PointerByReference();
        SunyardSdfLibrary.INSTANCE.SDF_OpenDevice(phDeviceHandle, safeStringBytes(ip), port, connTimeout, dealTimeout, 0);
        String key = UUID.randomUUID().toString();
        DEVICE_HANDLE_CONTEXT.put(key, phDeviceHandle.getValue());
        return key;
    }

    @Override
    protected int getAlgId(AlgId alg) {
        return SunyardAlgId.valueOf(alg.name()).getValue();
    }


    public static byte[] safeStringBytes(String str) {
        if (null == str || str.isEmpty()) {
            return new byte[]{0x30};
        }
        int len = str.getBytes().length;
        byte[] ret = new byte[len + 1];
        System.arraycopy(str.getBytes(), 0, ret, 0, len);
        return ret;
    }

}
