import { Database, RunResult, SQLiteValue } from 'node-sqlite3-wasm';
import System from '../System.js';

export interface RemovedItemRecord extends Record<string, SQLiteValue> {
    removal_id: string;
    table_name: string;
    entity_id: string;
    book_id: string | null;
    user_id: string;
    deleted_at: number;
}

/**
 * Repository for tracking deleted items for sync purposes.
 */
export default class RemovedItemsRepository {
    /**
     * Inserts a removal record into the database.
     * @param removalId - The unique ID for this removal record.
     * @param tableName - The name of the table from which the item is deleted.
     * @param entityId - The UUID of the deleted entity.
     * @param bookId - Book ID (null for series items).
     * @param userId - The user ID who owns the item.
     * @param deletedAt - Timestamp of deletion.
     * @param lang - The language for error messages ('fr' or 'en').
     * @returns True if inserted successfully.
     */
    public static insert(
        removalId: string,
        tableName: string,
        entityId: string,
        bookId: string | null,
        userId: string,
        deletedAt: number,
        lang: 'fr' | 'en'
    ): boolean {
        try {
            const db: Database = System.getDb();
            const query: string = `
                INSERT INTO removed_items (removal_id, table_name, entity_id, book_id, user_id, deleted_at)
                VALUES (?, ?, ?, ?, ?, ?)
                ON CONFLICT(table_name, entity_id) DO UPDATE SET deleted_at = excluded.deleted_at
            `;
            const params: SQLiteValue[] = [removalId, tableName, entityId, bookId, userId, deletedAt];
            const result: RunResult = db.run(query, params);
            return result.changes > 0;
        } catch (error: unknown) {
            if (error instanceof Error) {
                console.error(`DB Error: ${error.message}`);
                throw new Error(lang === 'fr' ? `Impossible d'enregistrer la suppression.` : `Unable to record deletion.`);
            } else {
                console.error("An unknown error occurred.");
                throw new Error(lang === 'fr' ? "Une erreur inconnue s'est produite." : "An unknown error occurred.");
            }
        }
    }

    /**
     * Retrieves deletions since a specific timestamp.
     * Used to get deletions that occurred since last sync.
     * @param userId - The user ID.
     * @param since - Timestamp to get deletions after.
     * @param lang - The language for error messages ('fr' or 'en').
     * @returns Array of removed item records.
     */
    public static getDeletionsSince(userId: string, since: number, lang: 'fr' | 'en'): RemovedItemRecord[] {
        try {
            const db: Database = System.getDb();
            const query: string = 'SELECT * FROM removed_items WHERE user_id = ? AND deleted_at > ?';
            const params: SQLiteValue[] = [userId, since];
            const records: RemovedItemRecord[] = db.all(query, params) as RemovedItemRecord[];
            return records;
        } catch (error: unknown) {
            if (error instanceof Error) {
                console.error(`DB Error: ${error.message}`);
                throw new Error(lang === 'fr' ? `Impossible de récupérer les suppressions.` : `Unable to retrieve deletions.`);
            } else {
                console.error("An unknown error occurred.");
                throw new Error(lang === 'fr' ? "Une erreur inconnue s'est produite." : "An unknown error occurred.");
            }
        }
    }

    /**
     * Checks if an entity was previously deleted.
     * @param tableName - The table name.
     * @param entityId - The entity ID.
     * @param lang - The language for error messages ('fr' or 'en').
     * @returns True if the entity was deleted locally.
     */
    public static wasDeleted(tableName: string, entityId: string, lang: 'fr' | 'en'): boolean {
        try {
            const db: Database = System.getDb();
            const query: string = 'SELECT 1 FROM removed_items WHERE table_name = ? AND entity_id = ? LIMIT 1';
            const params: SQLiteValue[] = [tableName, entityId];
            const result = db.get(query, params);
            return result !== null;
        } catch (error: unknown) {
            if (error instanceof Error) {
                console.error(`DB Error: ${error.message}`);
                throw new Error(lang === 'fr' ? `Impossible de vérifier si l'élément a été supprimé.` : `Unable to check if item was deleted.`);
            } else {
                console.error("An unknown error occurred.");
                throw new Error(lang === 'fr' ? "Une erreur inconnue s'est produite." : "An unknown error occurred.");
            }
        }
    }

    /**
     * Retrieves all tracked deletions for a specific book.
     * @param userId - The user ID.
     * @param bookId - The book ID.
     * @param lang - The language for error messages ('fr' or 'en').
     * @returns Array of removed item records for that book.
     */
    public static getDeletionsForBook(userId: string, bookId: string, lang: 'fr' | 'en'): RemovedItemRecord[] {
        try {
            const db: Database = System.getDb();
            const query: string = 'SELECT * FROM removed_items WHERE user_id = ? AND book_id = ?';
            const params: SQLiteValue[] = [userId, bookId];
            const records: RemovedItemRecord[] = db.all(query, params) as RemovedItemRecord[];
            return records;
        } catch (error: unknown) {
            if (error instanceof Error) {
                console.error(`DB Error: ${error.message}`);
                throw new Error(lang === 'fr' ? `Impossible de récupérer les suppressions pour ce livre.` : `Unable to retrieve deletions for this book.`);
            } else {
                console.error("An unknown error occurred.");
                throw new Error(lang === 'fr' ? "Une erreur inconnue s'est produite." : "An unknown error occurred.");
            }
        }
    }

    /**
     * Clears all deletion records for a user.
     * WARNING: Only use this when wiping user data completely.
     * @param userId - The user ID.
     * @param lang - The language for error messages ('fr' or 'en').
     * @returns True if cleared successfully.
     */
    public static clearAllForUser(userId: string, lang: 'fr' | 'en'): boolean {
        try {
            const db: Database = System.getDb();
            const query: string = 'DELETE FROM removed_items WHERE user_id = ?';
            const params: SQLiteValue[] = [userId];
            const result: RunResult = db.run(query, params);
            return result.changes > 0;
        } catch (error: unknown) {
            if (error instanceof Error) {
                console.error(`DB Error: ${error.message}`);
                throw new Error(lang === 'fr' ? `Impossible de supprimer les enregistrements de suppression.` : `Unable to clear deletion records.`);
            } else {
                console.error("An unknown error occurred.");
                throw new Error(lang === 'fr' ? "Une erreur inconnue s'est produite." : "An unknown error occurred.");
            }
        }
    }
}
