package info.knacki.pass.settings;

import android.content.Context;
import android.content.SharedPreferences;
import android.util.JsonReader;
import android.util.MalformedJsonException;

import java.io.File;
import java.io.IOException;
import java.io.StringReader;
import java.util.logging.Level;
import java.util.logging.Logger;

import info.knacki.gitdroid.GitConfig;
import info.knacki.gitdroid.io.NetworkUtils;
import info.knacki.pass.io.PathUtils;

public class SettingsManager {
    private static final Logger log = Logger.getLogger(SettingsManager.class.getName());

    public static class EncryptionType {
        public static final EncryptionType TYPE_RAW = new EncryptionType(0);
        public static final EncryptionType TYPE_GPG = new EncryptionType(1);
        public static final EncryptionType TYPE_PASSWORD = new EncryptionType(2);

        private final int fType;

        private EncryptionType(int type) {
            fType = type;
        }

        @Override
        public boolean equals(Object obj) {
            return obj != null && obj.getClass().equals(getClass()) && fType == ((EncryptionType)obj).fType;
        }

        public int IntValue() {
            return fType;
        }

        public static EncryptionType FromInt(int i) {
            if (i == TYPE_RAW.fType)
                return TYPE_RAW;
            else if (i == TYPE_PASSWORD.fType)
                return TYPE_PASSWORD;
            else if (i == TYPE_GPG.fType)
                return TYPE_GPG;
            return TYPE_RAW;
        }
    }

    public static abstract class VCS {
        static VCS factory(Context ctx, String system, String data) {
            if ("git".equals(system))
                return new Git(ctx, data);
            return null;
        }

        public abstract String GetName();
        public abstract String GetData();
    }

    public static class Git extends VCS implements NetworkUtils.AuthConfig, GitConfig {
        String fUrl;
        String fUser;
        String fPassword;
        boolean fPrivKey;
        String fBranch;
        String fUsername;
        String fUserEmail;
        private final Context fContext;

        Git(Context ctx, String data) {
            fContext = ctx;
            if (null == data || data.isEmpty()) {
                reset();
                return;
            }

            try {
                JsonReader reader = new JsonReader(new StringReader(data));
                if (!reader.hasNext())
                    throw new MalformedJsonException(data);
                reader.beginArray();
                if (!reader.hasNext())
                    throw new MalformedJsonException(data);
                reader.beginObject();
                while (reader.hasNext()) {
                    switch (reader.nextName()) {
                        case "url":
                            fUrl = reader.nextString();
                            break;
                        case "user":
                            fUser = reader.nextString();
                            break;
                        case "pass":
                            fPassword = reader.nextString();
                            break;
                        case "branch":
                            fBranch = reader.nextString();
                            break;
                        case "username":
                            fUsername = reader.nextString();
                            break;
                        case "email":
                            fUserEmail = reader.nextString();
                            break;
                        case "privKey":
                            fPrivKey = reader.nextBoolean();
                            break;
                    }
                }
                reader.close();
            }
            catch (IOException e) {
                log.log(Level.SEVERE, e.getMessage(), e);
                reset();
            }
        }

        public Git(Context ctx) {
            fContext = ctx;
            reset();
        }

        private void reset() {
            fUrl = "";
            fBranch = "";
            fUser = "";
            fPassword = "";
            fUsername = "";
            fUserEmail = "";
            fPrivKey = false;
        }

        public String GetName() {
            return "git";
        }

        public String SetUrl(String url) {
            if (url != null)
                fUrl = url;
            return fUrl;
        }

        public String GetUrl() {
            return fUrl;
        }

        public void SetPassword(String pass) {
            fPassword = pass;
        }

        @Override
        public String GetPassword() {
            return fPassword;
        }

        public void SetPrivateKey(boolean usePrivateKey) {
            fPrivKey = usePrivateKey;
        }

        @Override
        public String GetPrivateKey() {
            if (!fPrivKey)
                return null;
            String privKeyFile = PathUtils.GetPrivateRSAKey(fContext);
            return new File(privKeyFile).exists() ? privKeyFile : null;
        }

        public boolean HasPrivateKey() {
            return fPrivKey;
        }

        public void SetUser(String user) {
            fUser = user;
        }

        @Override
        public String GetUser() {
            return fUser;
        }

        @Override
        public String GetUsername() { return fUsername; }

        public void SetUsername(String val) { fUsername = val; }

        @Override
        public String GetUserEmail() { return fUserEmail; }

        public void SetUserEmail(String val) { fUserEmail = val; }

        public void SetBranch(String branch) {
            fBranch = branch;
        }

        @Override
        public String GetBranch() {
            return fBranch;
        }

        @Override
        public boolean HasAuthentication() {
            return !"".equals(fUser);
        }

        private static String jsonEscape(String in) {
            return in;
        }

        public String GetData() {
            return "[{" +
                    "\"url\":\"" +jsonEscape(fUrl) +"\"," +
                    "\"user\":\"" +jsonEscape(fUser) +"\"," +
                    "\"pass\":\"" +jsonEscape(fPassword) +"\"," +
                    "\"privKey\":" +(fPrivKey ? "true" : "false") +"," +
                    "\"branch\":\"" +jsonEscape(fBranch) +"\"," +
                    "\"username\":\"" +jsonEscape(fUsername) +"\"," +
                    "\"email\":\"" +jsonEscape(fUserEmail) +"\"" +
                    "}]";
        }
    }

    public final static String SHARED_PREF_FILE = "pass_prefs";
    @SuppressWarnings("SpellCheckingInspection") private static final String ENCRYPTION_PASSWORD = "encPasswd";
    private static final String FINGERPRINT_ACTIVE = "FingerprintEnabled";

    private static SharedPreferences GetPrefManager(Context c) {
        return c.getSharedPreferences(SHARED_PREF_FILE, Context.MODE_PRIVATE);
    }

    public static EncryptionType GetDefaultEncryptionType(Context ctx) {
        return EncryptionType.FromInt(GetPrefManager(ctx).getInt(EncryptionType.class.getSimpleName(), EncryptionType.TYPE_RAW.fType));
    }

    public static void SetDefaultEncryptionType(Context ctx, EncryptionType value) {
        GetPrefManager(ctx).edit().putInt(EncryptionType.class.getSimpleName(), value.IntValue()).apply();
    }

    public static VCS GetVCS(Context ctx) {
        SharedPreferences prefs = GetPrefManager(ctx);
        return VCS.factory(ctx, prefs.getString(VCS.class.getSimpleName(), ""), prefs.getString(VCS.class.getSimpleName()+"_data", ""));
    }

    public static void SetVCS(Context ctx, VCS vcs) {
        final SharedPreferences.Editor prefs = GetPrefManager(ctx).edit();
        if (vcs != null)
            prefs.putString(VCS.class.getSimpleName(), vcs.GetName()).putString(VCS.class.getSimpleName()+"_data", vcs.GetData()).apply();
        else
            prefs.remove(VCS.class.getSimpleName()).commit();
    }

    public static boolean HasPassword(Context ctx) {
        return !("".equals(GetPassword(ctx)));
    }

    public static String GetPassword(Context ctx) {
        return GetPrefManager(ctx).getString(ENCRYPTION_PASSWORD, "");
    }

    public static void SetPassword(Context ctx, String password) {
        GetPrefManager(ctx).edit().putString(ENCRYPTION_PASSWORD, password).apply();
    }

    public static boolean IsFingerprintEnabled(Context ctx) {
        return GetPrefManager(ctx).getBoolean(FINGERPRINT_ACTIVE, false);
    }

    public static void SetFingerprintEnabled(Context ctx, boolean value) {
        GetPrefManager(ctx).edit().putBoolean(FINGERPRINT_ACTIVE, value).apply();
    }
}
