package com.xiaoyudesign.rnupdate;
import android.content.Context;
import android.content.SharedPreferences;
import android.util.Log;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.zip.ZipEntry;
import java.util.zip.ZipInputStream;

public class UpdateContext {
    private Context context;
    private static UpdateContext sInstance;

    private static final Object sLock = new Object();
    private SharedPreferences sp;

    // 根目录
    private File rootDir;
    // 在files文件下的 目录名称
    private static final String UpdateDir = UpdateConstant.UpdateDir.getValue();
    private static final String PPK_ZIP_NAME = UpdateConstant.PPK_ZIP_NAME.getValue();
    // 存放于  files/{RootDir}/{currentVersion}/bundle的目录
    private static final String BundlePath = UpdateConstant.BundlePath.getValue();

    public File getPPKOutputFile(String versionCode) {
        return new File(rootDir,   versionCode + PPK_ZIP_NAME);
    }

    public UpdateContext(Context applicationContext) {
        this.context = applicationContext;

        this.rootDir = new File(context.getFilesDir(), UpdateDir);
        this.sp = context.getSharedPreferences("update", Context.MODE_PRIVATE);

        if (!rootDir.exists()) {
            rootDir.mkdir();
        }
    }

    public static UpdateContext getInstance(Context context) {
        if(sInstance == null) {
            synchronized (sLock) {
                if (sInstance == null) {
                    sInstance = new UpdateContext(context.getApplicationContext());
                }
            }
        }
        return sInstance;
    }

    public void setKv(String key, String value) {
        SharedPreferences.Editor editor = sp.edit();
        editor.putString(key, value);
        editor.apply();
    }

    public String getKv(String key) {
        return sp.getString(key, null);
    }

    public String getCurrentVersion() {
        return sp.getString("currentVersion", null);
    }

    public void updateCurrentVersion(String lastVersion) {
        SharedPreferences.Editor editor = sp.edit();
//        editor.putString("lastVersion", getCurrentVersion());
        editor.putString("currentVersion", lastVersion);
        editor.apply();
    }

    public static String getBundleUrl(Context context) {
        return getInstance(context).getBundleUrl();
    }

    public static String getBundleUrl(Context context, String defaultAssetsUrl) {
        return getInstance(context).getBundleUrl(defaultAssetsUrl);
    }

    public String getBundleUrl() {
        return this.getBundleUrl((String) null);
    }

    public String getBundleUrl(String defaultAssetsUrl) {
        String currentVersion = getCurrentVersion();
        if (currentVersion == null) {
            return defaultAssetsUrl;
        }

        while (currentVersion != null) {
            File bundleFile = new File(rootDir, currentVersion + BundlePath);
            if(!bundleFile.exists()) {
                // 当前版本的文件不存在，那就要尝试回滚到上一个版本
                currentVersion = this.rollBack();
                continue;
            }
            // 当前可用版本的路径
            return bundleFile.toString();
        }
        return defaultAssetsUrl;
    }

    /**
     * 回滚版本且记录版本信息
     * @return
     */
    private String rollBack() {
        String lastVersion = sp.getString("lastVersion", null);
        String currentVersion = sp.getString("currentVersion", null);
        SharedPreferences.Editor editor = sp.edit();
        if(lastVersion == null) {
            editor.remove("currentVersion");
        } else {
            editor.remove("lastVersion");
            editor.putString("currentVersion", lastVersion);
            editor.putString("rolledBackVersion", currentVersion);
        }
        editor.apply();
        return lastVersion;
    }

    public boolean extractZip(File zipFile, String newVersion) {
        try {
            if (!zipFile.exists()) {
                return false;
            }

            ZipInputStream zis = new ZipInputStream(new FileInputStream(zipFile));
            ZipEntry entry;

            while ((entry = zis.getNextEntry()) != null) {
                // 跳过__MACOSX目录和.DS_Store文件
                if (entry.getName().contains("__MACOSX") || entry.getName().contains(".DS_Store")) {
                    continue;
                }

                File entryFile = new File(rootDir, newVersion+"/"+ entry.getName());

                // 确保父目录存在
                if (entryFile.getParentFile() != null && !entryFile.getParentFile().exists()) {
                    entryFile.getParentFile().mkdirs();
                }

                // 创建目录
                if (entry.isDirectory()) {
                    entryFile.mkdirs();
                } else {
                    // 写入文件
                    FileOutputStream fos = new FileOutputStream(entryFile);
                    byte[] buffer = new byte[8192];
                    int len;
                    while ((len = zis.read(buffer)) != -1) {
                        fos.write(buffer, 0, len);
                    }
                    fos.close();
                }

                zis.closeEntry();
            }

            zis.close();
            // 删除zip文件
            zipFile.delete();
            return true;
        } catch (IOException e) {
            Log.e(UpdateContext.class.getName(), "extractZip: "+ e.getMessage());
        }
        return false;
    }

    /**
     * 检测版本文件是否存在
     * @param newVersion
     * @return
     */
    public boolean checkVersionExists(String newVersion) {
        return new File(rootDir, newVersion+BundlePath).exists();
    }

    /**
     * 切换版本
     * @param newVersion
     */
    public boolean switchVersion(String newVersion) {
        if (!this.checkVersionExists(newVersion)) {
            // throw new Error("Bundle version " + newVersion + " not found.");
            return false;
        }
        String lastVersion = getCurrentVersion();
        SharedPreferences.Editor editor = sp.edit();
        editor.putString("currentVersion", newVersion);
        if (lastVersion != null && !lastVersion.equals(newVersion)) {
            editor.putString("lastVersion", lastVersion);
        }
        editor.putString("rolledBackVersion", null);
        editor.apply();
        return true;
    }

}
