import { getUserEncryptionKey } from "../keyManager.js";
import System from "../System.js";
import { ActChapter } from "./Act.js";
import IncidentRepository, { IncidentQuery } from "../repositories/incident.repository.js";
import RemovedItem from "./RemovedItem.js";

export interface IncidentStory {
    incidentTitle: string;
    incidentSummary: string;
    chapterSummary: string;
    chapterGoal: string;
}

export interface SyncedIncident {
    id: string;
    name: string;
    lastUpdate: number;
}

export interface IncidentProps {
    incidentId: string;
    title: string;
    summary: string;
    chapters?: ActChapter[];
}

export default class Incident {
    /**
     * Creates a new incident for a book.
     * Encrypts the incident name and generates a hashed version for indexing.
     * @param userId - The unique identifier of the user creating the incident
     * @param bookId - The unique identifier of the book to add the incident to
     * @param name - The plain text name of the incident
     * @param lang - The language for error messages (defaults to 'fr')
     * @param existingIncidentId - Optional existing incident ID to use instead of generating a new one
     * @returns The unique identifier of the created incident
     */
    public static addNewIncident(
        userId: string,
        bookId: string,
        name: string,
        lang: 'fr' | 'en' = 'fr',
        existingIncidentId?: string
    ): string {
        const userKey: string = getUserEncryptionKey(userId);
        const encryptedName: string = System.encryptDataWithUserKey(name, userKey);
        const hashedName: string = System.hashElement(name);
        const incidentId: string = existingIncidentId || System.createUniqueId();
        return IncidentRepository.insertNewIncident(incidentId, userId, bookId, encryptedName, hashedName, lang);
    }

    /**
     * Retrieves all incidents for a specific book with their associated chapters.
     * Decrypts incident titles and summaries using the user's encryption key.
     * @param userId - The unique identifier of the user
     * @param bookId - The unique identifier of the book
     * @param actChapters - Array of chapters from acts to associate with incidents
     * @param lang - The language for error messages (defaults to 'fr')
     * @returns A promise resolving to an array of incident properties with decrypted data
     */
    public static async getIncitentsIncidents(
        userId: string,
        bookId: string,
        actChapters: ActChapter[],
        lang: 'fr' | 'en' = 'fr'
    ): Promise<IncidentProps[]> {
        const incidentQueryResults: IncidentQuery[] = IncidentRepository.fetchAllIncitentIncidents(userId, bookId, lang);
        const incidents: IncidentProps[] = [];
        const userKey: string = getUserEncryptionKey(userId);

        if (incidentQueryResults.length > 0) {
            for (const incidentRecord of incidentQueryResults) {
                const associatedChapters: ActChapter[] = [];
                for (const chapter of actChapters) {
                    if (chapter.incidentId === incidentRecord.incident_id) {
                        associatedChapters.push(chapter);
                    }
                }
                incidents.push({
                    incidentId: incidentRecord.incident_id,
                    title: incidentRecord.title ? System.decryptDataWithUserKey(incidentRecord.title, userKey) : '',
                    summary: incidentRecord.summary ? System.decryptDataWithUserKey(incidentRecord.summary, userKey) : '',
                    chapters: associatedChapters
                });
            }
        }
        return incidents;
    }

    /**
     * Removes an incident from a book.
     * @param userId - The unique identifier of the user
     * @param bookId - The unique identifier of the book
     * @param incidentId - The unique identifier of the incident to remove
     * @param deletedAt - The timestamp of deletion
     * @param lang - The language for error messages (defaults to 'fr')
     * @returns True if the incident was successfully deleted, false otherwise
     */
    public static removeIncident(
        userId: string,
        bookId: string,
        incidentId: string,
        deletedAt: number = System.timeStampInSeconds(),
        lang: 'fr' | 'en' = 'fr'
    ): boolean {
        const deleted: boolean = IncidentRepository.deleteIncident(userId, bookId, incidentId, lang);
        if (deleted) {
            RemovedItem.deleteTracker(userId, bookId, 'book_incidents', incidentId, deletedAt, lang);
        }
        return deleted;
    }
}
