import {Database, RunResult, SQLiteValue} from 'node-sqlite3-wasm'; import System from "../System.js"; export interface CharacterResult extends Record { character_id: string; first_name: string; last_name: string; title: string; category: string; image: string; role: string; biography: string; history: string; } export interface AttributeResult extends Record { attr_id: string; attribute_name: string; attribute_value: string; } export interface CompleteCharacterResult extends Record { character_id: string; first_name: string; last_name: string; category: string; title: string; role: string; biography: string; history: string; attribute_name: string; attribute_value: string; } export default class CharacterRepo { public static fetchCharacters(userId: string, bookId: string, lang: 'fr' | 'en' = 'fr'): CharacterResult[] { let result: CharacterResult[]; try { const db: Database = System.getDb(); result = db.all('SELECT character_id, first_name, last_name, title, category, image, role, biography, history FROM book_characters WHERE book_id=? AND user_id=?', [bookId, userId]) as CharacterResult[]; } catch (e: unknown) { if (e instanceof Error) { console.error(`DB Error: ${e.message}`); throw new Error(lang === 'fr' ? `Impossible de récupérer les personnages.` : `Unable to retrieve characters.`); } else { console.error("An unknown error occurred."); throw new Error(lang === 'fr' ? "Une erreur inconnue s'est produite." : "An unknown error occurred."); } } return result; } public static addNewCharacter(userId: string, characterId: string, encryptedName: string, encryptedLastName: string, encryptedTitle: string, encryptedCategory: string, encryptedImage: string, encryptedRole: string, encryptedBiography: string, encryptedHistory: string, bookId: string, lang: 'fr' | 'en' = 'fr'): string { let result: RunResult; try { const db: Database = System.getDb(); result = db.run('INSERT INTO `book_characters` (character_id, book_id, user_id, first_name, last_name, category, title, image, role, biography, history, last_update) VALUES (?,?,?,?,?,?,?,?,?,?,?,?)', [characterId, bookId, userId, encryptedName, encryptedLastName, encryptedCategory, encryptedTitle, encryptedImage, encryptedRole, encryptedBiography, encryptedHistory, System.timeStampInSeconds()]); } catch (e: unknown) { if (e instanceof Error) { console.error(`DB Error: ${e.message}`); throw new Error(lang === 'fr' ? `Impossible d'ajouter le personnage.` : `Unable to add character.`); } else { console.error("An unknown error occurred."); throw new Error(lang === 'fr' ? "Une erreur inconnue s'est produite." : "An unknown error occurred."); } } if (!result || result.changes === 0) { throw new Error(lang === 'fr' ? `Une erreur s'est produite lors de l'ajout du personnage.` : `Error adding character.`); } return characterId; } static insertAttribute(attributeId: string, characterId: string, userId: string, type: string, name: string, lang: 'fr' | 'en' = 'fr'): string { let result: RunResult; try { const db: Database = System.getDb(); result = db.run('INSERT INTO `book_characters_attributes` (attr_id, character_id, user_id, attribute_name, attribute_value, last_update) VALUES (?,?,?,?,?,?)', [attributeId, characterId, userId, type, name, System.timeStampInSeconds()]); } catch (e: unknown) { if (e instanceof Error) { console.error(`DB Error: ${e.message}`); throw new Error(lang === 'fr' ? `Impossible d'ajouter l'attribut.` : `Unable to add attribute.`); } else { console.error("An unknown error occurred."); throw new Error(lang === 'fr' ? "Une erreur inconnue s'est produite." : "An unknown error occurred."); } } if (!result || result.changes === 0) { throw new Error(lang === 'fr' ? `Une erreur s'est produite lors de l'ajout de l'attribut.` : `Error adding attribute.`); } return attributeId; } static updateCharacter(userId: string, id: number | null, encryptedName: string, encryptedLastName: string, encryptedTitle: string, encryptedCategory: string, encryptedImage: string, encryptedRole: string, encryptedBiography: string, encryptedHistory: string, lang: 'fr' | 'en' = 'fr'): boolean { try { const db: Database = System.getDb(); const result: RunResult = db.run('UPDATE `book_characters` SET `first_name`=?,`last_name`=?,`title`=?,`category`=?,`image`=?,`role`=?,`biography`=?,`history`=?,`last_update`=? WHERE `character_id`=? AND `user_id`=?', [encryptedName, encryptedLastName, encryptedTitle, encryptedCategory, encryptedImage, encryptedRole, encryptedBiography, encryptedHistory, System.timeStampInSeconds(), id, userId]); return result.changes > 0; } catch (e: unknown) { if (e instanceof Error) { console.error(`DB Error: ${e.message}`); throw new Error(lang === 'fr' ? `Impossible de mettre à jour le personnage.` : `Unable to update character.`); } else { console.error("An unknown error occurred."); throw new Error(lang === 'fr' ? "Une erreur inconnue s'est produite." : "An unknown error occurred."); } } } static deleteAttribute(userId: string, attributeId: string, lang: 'fr' | 'en' = 'fr'): boolean { try { const db: Database = System.getDb(); const result: RunResult = db.run('DELETE FROM `book_characters_attributes` WHERE `attr_id`=? AND `user_id`=?', [attributeId, userId]); return result.changes > 0; } catch (e: unknown) { if (e instanceof Error) { console.error(`DB Error: ${e.message}`); throw new Error(lang === 'fr' ? `Impossible de supprimer l'attribut.` : `Unable to delete attribute.`); } else { console.error("An unknown error occurred."); throw new Error(lang === 'fr' ? "Une erreur inconnue s'est produite." : "An unknown error occurred."); } } } static fetchAttributes(characterId: string, userId: string, lang: 'fr' | 'en' = 'fr'): AttributeResult[] { let result: AttributeResult[]; try { const db: Database = System.getDb(); result = db.all('SELECT attr_id, attribute_name, attribute_value FROM book_characters_attributes WHERE character_id=? AND user_id=?', [characterId, userId]) as AttributeResult[]; } catch (e: unknown) { if (e instanceof Error) { console.error(`DB Error: ${e.message}`); throw new Error(lang === 'fr' ? `Impossible de récupérer les attributs.` : `Unable to retrieve attributes.`); } else { console.error("An unknown error occurred."); throw new Error(lang === 'fr' ? "Une erreur inconnue s'est produite." : "An unknown error occurred."); } } return result; } static fetchCompleteCharacters(userId: string, bookId: string, tags: string[], lang: 'fr' | 'en' = 'fr'): CompleteCharacterResult[] { let result: CompleteCharacterResult[]; try { const db: Database = System.getDb(); let query: string = 'SELECT charac.character_id, first_name, last_name, category, title, role, biography, history, attribute_name, attribute_value FROM book_characters AS charac LEFT JOIN book_characters_attributes AS attr ON charac.character_id=attr.character_id WHERE charac.user_id=? AND charac.book_id=?'; let values: any[] = [userId, bookId]; if (tags && tags.length > 0) { const placeholders: string = tags.map((): string => '?').join(','); query += ` AND charac.character_id IN (${placeholders})`; values.push(...tags); } result = db.all(query, values) as CompleteCharacterResult[]; } catch (e: unknown) { if (e instanceof Error) { console.error(`DB Error: ${e.message}`); throw new Error(lang === 'fr' ? `Impossible de récupérer les personnages complets.` : `Unable to retrieve complete characters.`); } else { console.error("An unknown error occurred."); throw new Error(lang === 'fr' ? "Une erreur inconnue s'est produite." : "An unknown error occurred."); } } if (result.length === 0) { throw new Error(lang === 'fr' ? `Aucun personnage complet trouvé.` : `No complete characters found.`); } return result; } }