package com.sf.sdk.demo.safety;

import android.annotation.SuppressLint;
import android.content.Context;
import android.os.Build;
import android.provider.Settings;

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileReader;
import java.io.FileWriter;
import java.nio.charset.StandardCharsets;
import java.security.MessageDigest;
import java.util.Objects;

/**
 * 存档管理
 */
public class ArchiveManager {

    private static final String DIR_ARCHIVE = "Archive";

    /**
     * 写入存档
     *
     * @param context  上下文
     * @param data     存档数据
     * @param fileName 文件名
     */
    public static boolean writeArchive(Context context, String data, String fileName) {
        String aesKey = getAesKey(context);
        String rawIV = generateRawIV(context);
        String aesIv = getAesIv(context, rawIV);
        String hash = md5(data);
        String encryptData = AES.encrypt(aesKey, aesIv, data);
        StringBuilder builder = new StringBuilder();
        builder.append("1");            // 存档类型
        builder.append("|");
        builder.append("10");           // 版本号
        builder.append("|");
        builder.append(hash);           // 源数据哈希
        builder.append("|");
        builder.append(rawIV);          // 初始向量
        builder.append(System.lineSeparator());
        builder.append(encryptData);    // 加密数据
        String content = builder.toString();
        try {
            File file = getFile(context, fileName);
            BufferedWriter writer = new BufferedWriter(new FileWriter(file));
            writer.write(content);
            writer.flush();
            writer.close();
            return true;
        } catch (Exception e) {
            e.printStackTrace();
        }
        return false;
    }

    /**
     * 读取存档
     *
     * @param context  上下文
     * @param fileName 文件名
     */
    public static String readArchive(Context context, String fileName) {
        try {
            String line;
            String header = null;
            String data = null;
            File file = getFile(context, fileName);
            BufferedReader reader = new BufferedReader(new FileReader(file));
            while ((line = reader.readLine()) != null) {
                if (header == null) {
                    header = line;
                } else if (data == null) {
                    data = line;
                }
            }
            reader.close();
            if (header != null && data != null) {
                String[] split = header.split("\\|");
                String hash = split.length > 2 ? split[2] : null;   // 源数据哈希
                String rawIV = split.length > 3 ? split[3] : null;  // 初始向量
                String aesKey = getAesKey(context);
                String aesIv = getAesIv(context, rawIV);
                String decryptData = AES.decrypt(aesKey, aesIv, data);
                if (Objects.equals(hash, md5(decryptData))) {   // 校验存档内容哈希值
                    return decryptData;
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

    private static File getFile(Context context, String fileName) {
        File filesDir = context.getExternalFilesDir(DIR_ARCHIVE);
        if (!filesDir.exists() && !filesDir.mkdirs()) {
            filesDir = new File(context.getFilesDir(), DIR_ARCHIVE);
        }
        return new File(filesDir, fileName);
    }

    public static String getAesKey(Context context) {
        String key = Build.FINGERPRINT + '/' + context.getPackageName() + '/' + getAndroidId(context);
        return md5(key);
    }

    public static String getAesIv(Context context, String rawIv) {
        String iv = rawIv + '/' + getAndroidId(context);
        return md5(iv).substring(0, 16);
    }

    private static String generateRawIV(Context context) {
        return md5(context.getPackageName() + '/' + System.currentTimeMillis());
    }

    @SuppressLint("HardwareIds")
    private static String getAndroidId(Context context) {
        try {
            return Settings.Secure.getString(context.getContentResolver(), Settings.Secure.ANDROID_ID);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return "";
    }

    private static String md5(String data) {
        return digest("MD5", data);
    }

    private static String sha256(String data) {
        return digest("SHA-256", data);
    }

    private static String digest(String algorithm, String data) {
        try {
            MessageDigest digest = MessageDigest.getInstance(algorithm);
            byte[] bytes = digest.digest(data.getBytes(StandardCharsets.UTF_8));
            return byte2Hex(bytes);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

    private static String byte2Hex(byte[] bytes) {
        String hex;
        StringBuilder builder = new StringBuilder();
        for (byte b : bytes) {
            hex = Integer.toHexString(b & 0XFF);
            if (hex.length() == 1) {
                builder.append("0");
            }
            builder.append(hex);
        }
        return builder.toString();
    }

}
