package com.secureline.notes.data;

import android.content.ContentValues;
import android.content.Context;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;

import com.secureline.notes.BuildConfig;
import com.secureline.notes.crypto.CryptoManager;
import com.secureline.notes.security.SessionManager;

import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.List;

public class NotesRepository {

    private final NotesDatabaseHelper dbHelper;

    public NotesRepository(Context ctx) {
        dbHelper = new NotesDatabaseHelper(ctx);
    }

    // 🔒 ACCESS CONTROL
    private void enforceUnlocked() {
        if (!SessionManager.isUnlocked()) {
            throw new SecurityException("notes locked");
        }
    }

    // 🔧 null-safe helper (cleaner code)
    private String safe(String s) {
        return s == null ? "" : s;
    }

    public List<Note> getAll() {

        enforceUnlocked();
        SessionManager.refresh();

        List<Note> list = new ArrayList<>();

        SQLiteDatabase db = dbHelper.getReadableDatabase();
        if (db == null || !db.isOpen()) {
            return list;
        }

        Cursor c = null;

        try {

            c = db.query("notes", null, null, null, null, null, "updated DESC");

            while (c.moveToNext()) {

                long id = c.getLong(c.getColumnIndexOrThrow("id"));
                String title = safe(c.getString(c.getColumnIndexOrThrow("title")));
                byte[] encrypted = c.getBlob(c.getColumnIndexOrThrow("content"));

                String content = "";

                if (encrypted != null) {

                    byte[] decrypted = null;

                    try {
                        decrypted = CryptoManager.decryptLocal(encrypted);
                        content = new String(decrypted, StandardCharsets.UTF_8);
                    } catch (Exception e) {
                        if (BuildConfig.DEBUG) {
                            e.printStackTrace();
                        }
                    } finally {
                        if (decrypted != null) {
                            for (int i = 0; i < decrypted.length; i++) {
                                decrypted[i] = 0;
                            }
                        }
                    }
                }

                long updated = c.getLong(c.getColumnIndexOrThrow("updated"));

                list.add(new Note(id, title, content, updated));
            }

        } finally {
            if (c != null) c.close();
        }

        return list;
    }

    public Note getById(long id) {

        enforceUnlocked();
        SessionManager.refresh();

        SQLiteDatabase db = dbHelper.getReadableDatabase();
        if (db == null || !db.isOpen()) {
            return null;
        }

        Cursor c = null;

        try {

            c = db.query(
                    "notes",
                    null,
                    "id=?",
                    new String[]{String.valueOf(id)},
                    null,
                    null,
                    null
            );

            if (c == null || !c.moveToFirst()) {
                return null;
            }

            String title = safe(c.getString(c.getColumnIndexOrThrow("title")));
            byte[] encrypted = c.getBlob(c.getColumnIndexOrThrow("content"));

            String content = "";

            if (encrypted != null) {

                byte[] decrypted = null;

                try {
                    decrypted = CryptoManager.decryptLocal(encrypted);
                    content = new String(decrypted, StandardCharsets.UTF_8);
                } catch (Exception e) {
                    if (BuildConfig.DEBUG) {
                        e.printStackTrace();
                    }
                } finally {
                    if (decrypted != null) {
                        for (int i = 0; i < decrypted.length; i++) {
                            decrypted[i] = 0;
                        }
                    }
                }
            }

            long updated = c.getLong(c.getColumnIndexOrThrow("updated"));

            return new Note(id, title, content, updated);

        } finally {
            if (c != null) c.close();
        }
    }

    public long insert(String title, String content) {

        enforceUnlocked();
        SessionManager.refresh();

        byte[] plain = safe(content).getBytes(StandardCharsets.UTF_8);

        try {

            byte[] encrypted = CryptoManager.encryptLocal(plain);

            ContentValues v = new ContentValues();
            v.put("title", safe(title));
            v.put("content", encrypted);
            v.put("updated", System.currentTimeMillis());

            SQLiteDatabase db = dbHelper.getWritableDatabase();
            if (db == null || !db.isOpen()) {
                return -1;
            }

            long result = db.insert("notes", null, v);

            if (result == -1 && BuildConfig.DEBUG) {
                System.err.println("Insert failed");
            }

            return result;

        } catch (Exception e) {

            if (BuildConfig.DEBUG) {
                e.printStackTrace();
            }

            return -1;

        } finally {
            for (int i = 0; i < plain.length; i++) {
                plain[i] = 0;
            }
        }
    }

    public void update(long id, String title, String content) {

        enforceUnlocked();
        SessionManager.refresh();

        byte[] plain = safe(content).getBytes(StandardCharsets.UTF_8);

        try {

            byte[] encrypted = CryptoManager.encryptLocal(plain);

            ContentValues v = new ContentValues();
            v.put("title", safe(title));
            v.put("content", encrypted);
            v.put("updated", System.currentTimeMillis());

            SQLiteDatabase db = dbHelper.getWritableDatabase();
            if (db == null || !db.isOpen()) {
                return;
            }

            db.update(
                    "notes",
                    v,
                    "id=?",
                    new String[]{String.valueOf(id)}
            );

        } catch (Exception e) {

            if (BuildConfig.DEBUG) {
                e.printStackTrace();
            }

        } finally {
            for (int i = 0; i < plain.length; i++) {
                plain[i] = 0;
            }
        }
    }

    public void delete(long id) {

        enforceUnlocked();
        SessionManager.refresh();

        SQLiteDatabase db = dbHelper.getWritableDatabase();
        if (db == null || !db.isOpen()) {
            return;
        }

        db.delete(
                "notes",
                "id=?",
                new String[]{String.valueOf(id)}
        );
    }

    public void deleteAll() {

        enforceUnlocked();
        SessionManager.refresh();

        SQLiteDatabase db = dbHelper.getWritableDatabase();
        if (db == null || !db.isOpen()) {
            return;
        }

        db.beginTransaction();
        try {
            ContentValues wipe = new ContentValues();
            wipe.put("title", "");
            wipe.put("content", new byte[0]);

            db.update("notes", wipe, null, null);
            db.delete("notes", null, null);

            db.setTransactionSuccessful();

        } catch (Exception e) {
            if (BuildConfig.DEBUG) e.printStackTrace();
        } finally {
            db.endTransaction();
        }

        try {
            db.execSQL("PRAGMA wal_checkpoint(FULL)");
            db.execSQL("VACUUM");
        } catch (Exception ignored) {}
    }
}
