/**
 * POS local persistence: checkout outbox (IndexedDB) + cart holds.
 * Used by pos.html only. Checkout replay uses Firebase posCheckoutAck/{clientRequestId} for idempotency.
 */

const DB_NAME = 'pos-suite-v1';
const DB_VERSION = 1;
const STORE_OUTBOX = 'checkoutOutbox';
const STORE_HOLDS = 'cartHolds';

/** @returns {Promise<IDBDatabase>} */
export function openPosSuiteDB() {
    return new Promise((resolve, reject) => {
        const req = indexedDB.open(DB_NAME, DB_VERSION);
        req.onerror = () => reject(req.error || new Error('IndexedDB open failed'));
        req.onsuccess = () => resolve(req.result);
        req.onupgradeneeded = (e) => {
            const db = /** @type {IDBDatabase} */ (e.target.result);
            if (!db.objectStoreNames.contains(STORE_OUTBOX)) {
                db.createObjectStore(STORE_OUTBOX, { keyPath: 'id' });
            }
            if (!db.objectStoreNames.contains(STORE_HOLDS)) {
                db.createObjectStore(STORE_HOLDS, { keyPath: 'holdId' });
            }
        };
    });
}

/**
 * @param {IDBDatabase} db
 * @param {string} clientId
 * @param {object} row
 * @param {string} row.id
 * @param {string} row.clientId
 * @param {object} row.payload intent JSON
 * @param {number} row.createdAt
 * @param {string} [row.lastError]
 * @param {number} [row.attempts]
 */
export async function enqueuePosCheckoutOutbox(db, clientId, row) {
    const rec = {
        id: row.id,
        clientId: String(clientId || ''),
        payload: row.payload,
        createdAt: Number(row.createdAt) || Date.now(),
        lastError: row.lastError || '',
        attempts: Number(row.attempts) || 0
    };
    await new Promise((resolve, reject) => {
        const tx = db.transaction(STORE_OUTBOX, 'readwrite');
        tx.oncomplete = () => resolve();
        tx.onerror = () => reject(tx.error || new Error('IDB transaction failed'));
        tx.onabort = () => reject(tx.error || new Error('IDB transaction aborted'));
        tx.objectStore(STORE_OUTBOX).put(rec);
    });
}

/**
 * @param {IDBDatabase} db
 * @param {string} clientId
 * @returns {Promise<object[]>}
 */
export async function listPendingCheckoutOutbox(db, clientId) {
    const cid = String(clientId || '');
    const all = await new Promise((resolve, reject) => {
        const tx = db.transaction(STORE_OUTBOX, 'readonly');
        tx.onerror = () => reject(tx.error);
        const r = tx.objectStore(STORE_OUTBOX).getAll();
        r.onsuccess = () => resolve(r.result || []);
        r.onerror = () => reject(r.error);
    });
    return (all || []).filter((x) => x && x.clientId === cid).sort((a, b) => (a.createdAt || 0) - (b.createdAt || 0));
}

/**
 * @param {IDBDatabase} db
 * @param {string} id
 */
export async function removeCheckoutOutboxRow(db, id) {
    await new Promise((resolve, reject) => {
        const tx = db.transaction(STORE_OUTBOX, 'readwrite');
        tx.oncomplete = () => resolve();
        tx.onerror = () => reject(tx.error || new Error('IDB transaction failed'));
        tx.objectStore(STORE_OUTBOX).delete(String(id));
    });
}

/**
 * @param {IDBDatabase} db
 * @param {string} id
 * @param {string} err
 */
export async function markCheckoutOutboxError(db, id, err) {
    await new Promise((resolve, reject) => {
        const tx = db.transaction(STORE_OUTBOX, 'readwrite');
        tx.oncomplete = () => resolve();
        tx.onerror = () => reject(tx.error || new Error('IDB transaction failed'));
        const store = tx.objectStore(STORE_OUTBOX);
        const g = store.get(String(id));
        g.onsuccess = () => {
            const cur = g.result;
            if (cur) {
                cur.lastError = String(err || '').slice(0, 500);
                cur.attempts = Number(cur.attempts || 0) + 1;
                store.put(cur);
            }
        };
        g.onerror = () => reject(g.error);
    });
}

/**
 * @param {IDBDatabase} db
 * @param {object} hold
 */
export async function putCartHold(db, hold) {
    await new Promise((resolve, reject) => {
        const tx = db.transaction(STORE_HOLDS, 'readwrite');
        tx.oncomplete = () => resolve();
        tx.onerror = () => reject(tx.error || new Error('IDB transaction failed'));
        tx.objectStore(STORE_HOLDS).put(hold);
    });
}

/**
 * @param {IDBDatabase} db
 * @param {string} clientId
 */
export async function listCartHolds(db, clientId) {
    const cid = String(clientId || '');
    const all = await new Promise((resolve, reject) => {
        const tx = db.transaction(STORE_HOLDS, 'readonly');
        tx.onerror = () => reject(tx.error);
        const r = tx.objectStore(STORE_HOLDS).getAll();
        r.onsuccess = () => resolve(r.result || []);
        r.onerror = () => reject(r.error);
    });
    return (all || []).filter((h) => h && h.clientId === cid).sort((a, b) => (b.savedAt || 0) - (a.savedAt || 0));
}

/**
 * @param {IDBDatabase} db
 * @param {string} holdId
 */
export async function removeCartHold(db, holdId) {
    await new Promise((resolve, reject) => {
        const tx = db.transaction(STORE_HOLDS, 'readwrite');
        tx.oncomplete = () => resolve();
        tx.onerror = () => reject(tx.error || new Error('IDB transaction failed'));
        tx.objectStore(STORE_HOLDS).delete(String(holdId));
    });
}
