import { getUserEncryptionKey } from "../keyManager.js";
import System from "../System.js";
import { ActChapter } from "./Act.js";
import PlotPointRepository, { PlotPointQuery } from "../repositories/plotpoint.repository.js";
import RemovedItem from "./RemovedItem.js";

export interface PlotPointStory {
    plotTitle: string;
    plotSummary: string;
    chapterSummary: string;
    chapterGoal: string;
}

export interface PlotPointProps {
    plotPointId: string,
    title: string,
    summary: string,
    linkedIncidentId: string | null,
    chapters?: ActChapter[]
}

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

export default class PlotPoint {
    /**
     * Retrieves all plot points for a specific book with their associated chapters.
     * Decrypts plot point 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 act chapters to associate with plot points
     * @param lang - The language for error messages ('fr' or 'en'), defaults to 'fr'
     * @returns A promise resolving to an array of plot point properties with their associated chapters
     */
    public static async getPlotPoints(
        userId: string,
        bookId: string,
        actChapters: ActChapter[],
        lang: 'fr' | 'en' = 'fr'
    ): Promise<PlotPointProps[]> {
        const plotPointQueryResults: PlotPointQuery[] = PlotPointRepository.fetchAllPlotPoints(userId, bookId, lang);
        const userEncryptionKey: string = getUserEncryptionKey(userId);
        const plotPoints: PlotPointProps[] = [];

        if (plotPointQueryResults.length > 0) {
            for (const plotPointRow of plotPointQueryResults) {
                const associatedChapters: ActChapter[] = [];

                for (const chapter of actChapters) {
                    if (chapter.plotPointId === plotPointRow.plot_point_id) {
                        associatedChapters.push(chapter);
                    }
                }

                plotPoints.push({
                    plotPointId: plotPointRow.plot_point_id,
                    title: plotPointRow.title ? System.decryptDataWithUserKey(plotPointRow.title, userEncryptionKey) : '',
                    summary: plotPointRow.summary ? System.decryptDataWithUserKey(plotPointRow.summary, userEncryptionKey) : '',
                    linkedIncidentId: plotPointRow.linked_incident_id,
                    chapters: associatedChapters
                });
            }
        }

        return plotPoints;
    }

    /**
     * Creates a new plot point for a book, encrypting the name before storage.
     * @param userId - The unique identifier of the user
     * @param bookId - The unique identifier of the book
     * @param incidentId - The identifier of the linked incident
     * @param name - The name/title of the plot point
     * @param lang - The language for error messages ('fr' or 'en'), defaults to 'fr'
     * @param existingPlotPointId - Optional existing plot point ID to use instead of generating a new one
     * @returns The unique identifier of the created plot point
     */
    static addNewPlotPoint(
        userId: string,
        bookId: string,
        incidentId: string,
        name: string,
        lang: 'fr' | 'en' = 'fr',
        existingPlotPointId?: string
    ): string {
        const userEncryptionKey: string = getUserEncryptionKey(userId);
        const encryptedName: string = System.encryptDataWithUserKey(name, userEncryptionKey);
        const hashedName: string = System.hashElement(name);
        const plotPointId: string = existingPlotPointId || System.createUniqueId();

        return PlotPointRepository.insertNewPlotPoint(plotPointId, userId, bookId, encryptedName, hashedName, incidentId, lang);
    }

    /**
     * Removes a plot point from the database.
     * @param userId - The unique identifier of the user
     * @param bookId - The unique identifier of the book
     * @param plotId - The unique identifier of the plot point to remove
     * @param deletedAt - The timestamp of deletion
     * @param lang - The language for error messages ('fr' or 'en'), defaults to 'fr'
     * @returns True if the plot point was successfully deleted, false otherwise
     */
    static removePlotPoint(userId: string, bookId: string, plotId: string, deletedAt: number = System.timeStampInSeconds(), lang: 'fr' | 'en' = 'fr'): boolean {
        const deleted: boolean = PlotPointRepository.deletePlotPoint(userId, plotId, lang);
        if (deleted) {
            RemovedItem.deleteTracker(userId, bookId, 'book_plot_points', plotId, deletedAt, lang);
        }
        return deleted;
    }
}
