package util;

import com.alibaba.fastjson.JSONObject;
import exception.ZXChainException;
import org.apache.commons.lang3.StringUtils;

import java.io.*;
import java.net.HttpURLConnection;
import java.net.URL;
import java.nio.charset.StandardCharsets;
import java.util.Arrays;
import java.util.Locale;
import java.util.Objects;
import java.util.concurrent.TimeoutException;
import java.util.stream.Collectors;

public class Tools {
    public static JSONObject getJson(Object obj) {
        return JSONObject.parseObject(JSONObject.toJSONString(obj));
    }

    public static <T> T toJavaClass(Object input, Class<T> clazz){
        JSONObject jsonObject;

        if (input instanceof JSONObject) {
            jsonObject = (JSONObject) input;
        } else if (input instanceof String) {
            jsonObject = JSONObject.parseObject((String) input);
        } else {
            // 尝试将对象序列化为JSON字符串，然后再解析为JSONObject
            jsonObject = JSONObject.parseObject(JSONObject.toJSONString(input));
        }

        return JSONObject.toJavaObject(jsonObject, clazz);
    }

    public static String getHash(String fileUrl) throws Exception {
        byte[] bytesByFile = getFiles(fileUrl);
        return ZxlSDKUtil.sm3Hash(bytesByFile);
    }

    /**
     * 判断zxchain是否超时
     * @param timeBegin 开始时间
     * @param timeout 超时时常
     * @return true未超时
     */
    public static Boolean checkTimeout(long timeBegin, long timeout) throws TimeoutException {
        if (System.currentTimeMillis()-timeBegin > timeout) {
            throw new TimeoutException("zxchain time out");
        }

        return true;
    }

    /**
     * 简单的身份证验证算法
     * @param idCardNumber 身份证号
     * @return
     */
    public static boolean checkIdCard(String idCardNumber) {
        int[] weight = {7, 9, 10, 5, 8, 4, 2, 1, 6, 3, 7, 9, 10, 5, 8, 4, 2};
        byte[] validValue = {'1', '0', 'X', '9', '8', '7', '6', '5', '4', '3', '2'};
        if (!idCardNumber.matches("^[1-9]\\d{5}(18|19|20)\\d{2}(0[1-9]|1[0-2])(0[1-9]|[12][0-9]|3[01])\\d{3}([0-9Xx])$")) {
            return false;
        }

        String upCard = idCardNumber.toUpperCase(Locale.ROOT);
        byte[] cardBytes = upCard.getBytes(StandardCharsets.UTF_8);
        int nSum = 0;
        for (int i = 0; i < cardBytes.length-1; i++) {
            nSum += (cardBytes[i] - '0') * weight[i];
        }

        return validValue[nSum % 11] == cardBytes[17];
    }

    public static byte[] getFiles(String fileUrl) throws IOException {
        if (fileUrl.startsWith("http")) {
            return getNetworkFiles(fileUrl);
        }

        return getLocalFiles(fileUrl);
    }

    //读取本地文件
    public static byte[] getLocalFiles(String pathStr) throws IOException {
        File file = new File(pathStr);

        if (!file.exists()) {
            throw new FileNotFoundException("File not found: " + pathStr);
        }

        try (FileInputStream inputStream = new FileInputStream(file);
             ByteArrayOutputStream os = new ByteArrayOutputStream()) {

            byte[] buffer = new byte[8192]; // Adjust buffer size as needed (e.g., 8 KiB)
            int numRead;
            while ((numRead = inputStream.read(buffer)) != -1) {
                os.write(buffer, 0, numRead);
            }

            return os.toByteArray();
        }
    }

    //读网络文件
    public static byte[] getNetworkFiles(String fileUrl) throws IOException {
        if (StringUtils.isEmpty(fileUrl)) {
            throw new IllegalArgumentException("fileUrl cannot be null or empty");
        }

        URL url = new URL(fileUrl);
        HttpURLConnection conn = (HttpURLConnection) url.openConnection();

        conn.setRequestMethod("GET");
        conn.setConnectTimeout(4 * 1000);

        long contentLength = conn.getContentLengthLong();
        int bufferSize = (int) Math.min(contentLength, 8_192); // Default buffer size is 8 KiB
        if (contentLength > Integer.MAX_VALUE) {
            throw new IOException("Content length exceeds the maximum supported size");
        }

        try (InputStream inputStream = conn.getInputStream();
             ByteArrayOutputStream os = new ByteArrayOutputStream((int) Math.min(contentLength, Integer.MAX_VALUE))) {

            byte[] buffer = new byte[bufferSize];
            int numRead;
            while ((numRead = inputStream.read(buffer)) != -1) {
                os.write(buffer, 0, numRead);
            }

            return os.toByteArray();
        }
    }

    public static String getSignData(Object ...args){
        return Arrays.stream(args)
                .map(o -> o != null ? o.toString() : "")
                .collect(Collectors.joining("_"));
    }
}
