/**
 * IndexedDB-based message body storage for Android/browser.
 * Mirrors FileMessageStore API from @bobfrankston/mailx-store.
 * Stores RFC 2822 message bodies as blobs keyed by accountId/folderId/uid.
 */

const DB_NAME = "mailx-bodies";
const DB_VERSION = 1;
const STORE_NAME = "messages";

function openDb(): Promise<IDBDatabase> {
    return new Promise((resolve, reject) => {
        const req = indexedDB.open(DB_NAME, DB_VERSION);
        req.onupgradeneeded = () => {
            const db = req.result;
            if (!db.objectStoreNames.contains(STORE_NAME)) {
                db.createObjectStore(STORE_NAME);
            }
        };
        req.onsuccess = () => resolve(req.result);
        req.onerror = () => reject(req.error);
    });
}

function makeKey(accountId: string, folderId: number, uid: number): string {
    return `${accountId}/${folderId}/${uid}`;
}

export class WebMessageStore {
    private dbPromise: Promise<IDBDatabase>;

    constructor() {
        this.dbPromise = openDb();
    }

    async putMessage(accountId: string, folderId: number, uid: number, raw: Uint8Array | ArrayBuffer): Promise<string> {
        const db = await this.dbPromise;
        const key = makeKey(accountId, folderId, uid);
        const data = raw instanceof Uint8Array ? raw.buffer.slice(raw.byteOffset, raw.byteOffset + raw.byteLength) : raw;
        return new Promise((resolve, reject) => {
            const tx = db.transaction(STORE_NAME, "readwrite");
            tx.objectStore(STORE_NAME).put(data, key);
            tx.oncomplete = () => resolve(key);
            tx.onerror = () => reject(tx.error);
        });
    }

    async getMessage(accountId: string, folderId: number, uid: number): Promise<Uint8Array | null> {
        const db = await this.dbPromise;
        const key = makeKey(accountId, folderId, uid);
        return new Promise((resolve, reject) => {
            const tx = db.transaction(STORE_NAME, "readonly");
            const req = tx.objectStore(STORE_NAME).get(key);
            req.onsuccess = () => {
                if (req.result) {
                    resolve(new Uint8Array(req.result as ArrayBuffer));
                } else {
                    resolve(null);
                }
            };
            req.onerror = () => reject(req.error);
        });
    }

    async deleteMessage(accountId: string, folderId: number, uid: number): Promise<void> {
        const db = await this.dbPromise;
        const key = makeKey(accountId, folderId, uid);
        return new Promise((resolve, reject) => {
            const tx = db.transaction(STORE_NAME, "readwrite");
            tx.objectStore(STORE_NAME).delete(key);
            tx.oncomplete = () => resolve();
            tx.onerror = () => reject(tx.error);
        });
    }

    async hasMessage(accountId: string, folderId: number, uid: number): Promise<boolean> {
        const db = await this.dbPromise;
        const key = makeKey(accountId, folderId, uid);
        return new Promise((resolve, reject) => {
            const tx = db.transaction(STORE_NAME, "readonly");
            const req = tx.objectStore(STORE_NAME).count(IDBKeyRange.only(key));
            req.onsuccess = () => resolve(req.result > 0);
            req.onerror = () => reject(req.error);
        });
    }

    /** Clear all stored bodies — used for "Reset Store" */
    async clear(): Promise<void> {
        const db = await this.dbPromise;
        return new Promise((resolve, reject) => {
            const tx = db.transaction(STORE_NAME, "readwrite");
            tx.objectStore(STORE_NAME).clear();
            tx.oncomplete = () => resolve();
            tx.onerror = () => reject(tx.error);
        });
    }
}
