package com.secureline.notes.export;

import android.content.Context;

import com.secureline.notes.crypto.CryptoManager;
import com.secureline.notes.data.NotesRepository;

import org.json.JSONArray;
import org.json.JSONObject;

import java.nio.charset.StandardCharsets;

public class ImportManager {

    private static final int MAX_IMPORT_SIZE = 5 * 1024 * 1024;
    private static final int MAX_DECRYPTED_SIZE = 6 * 1024 * 1024;
    private static final int MAX_NOTES = 500;
    private static final int MAX_TEXT_LENGTH = 10000;

    public static void importFile(
            Context ctx,
            byte[] fileData,
            String password
    ) throws Exception {

        if (ctx == null)
            throw new IllegalArgumentException("context null");

        if (password == null || password.length() < 8)
            throw new IllegalArgumentException("weak password");

        if (fileData == null || fileData.length == 0 || fileData.length > MAX_IMPORT_SIZE)
            throw new IllegalArgumentException("invalid file size");

        byte[] decrypted = null;

        try {

            try {
                decrypted = CryptoManager.decryptExport(fileData, password);
            } catch (Exception e) {
                throw new IllegalArgumentException("decrypt failed", e);
            } finally {
                password = null;
            }

            if (decrypted == null || decrypted.length == 0 || decrypted.length > MAX_DECRYPTED_SIZE)
                throw new IllegalArgumentException("invalid decrypted size");

            JSONObject root;
            try {
                root = new JSONObject(new String(decrypted, StandardCharsets.UTF_8));
            } catch (Exception e) {
                throw new IllegalArgumentException("invalid json", e);
            }

            if (!root.has("format") || !root.has("version"))
                throw new IllegalArgumentException("invalid structure");

            String format = root.optString("format", "");
            int version = root.optInt("version", -1);

            if (version != 1)
                throw new IllegalArgumentException("unsupported version");

            NotesRepository repo = new NotesRepository(ctx);

            if ("lzn_note".equals(format)
                    || "sln_note".equals(format)) {

                String title = safeText(root.optString("title", ""));
                String content = safeText(root.optString("content", ""));

                if (repo.insert(title, content) == -1)
                    throw new IllegalStateException("db insert failed");

                return;
            }

            if ("lemenzo_notes".equals(format)
                    || "secureline_notes".equals(format)) {

                if (!root.has("notes"))
                    throw new IllegalArgumentException("invalid notes");

                JSONArray notes = root.getJSONArray("notes");

                int count = notes.length();

                if (count == 0)
                    return;

                if (count > MAX_NOTES)
                    throw new IllegalArgumentException("too many notes");

                for (int i = 0; i < count; i++) {

                    JSONObject n = notes.optJSONObject(i);
                    if (n == null) continue;

                    String title = safeText(n.optString("title", ""));
                    String content = safeText(n.optString("content", ""));

                    if (repo.insert(title, content) == -1)
                        throw new IllegalStateException("db insert failed");
                }

                return;
            }

            throw new IllegalArgumentException("invalid format");

        } finally {

            if (decrypted != null) {
                for (int i = 0; i < decrypted.length; i++) {
                    decrypted[i] = 0;
                }
            }
        }
    }

    private static String safeText(String input) {
        if (input == null) return "";

        if (input.length() > MAX_TEXT_LENGTH) {
            return input.substring(0, MAX_TEXT_LENGTH);
        }

        return input;
    }
}
