import { getUserEncryptionKey } from "../keyManager.js";
import System from "../System.js";
import GuidelineRepo, { GuideLineAIQuery, GuideLineQuery } from "../repositories/guideline.repository.js";

export interface SyncedGuideLine {
    lastUpdate: number;
}

export interface SyncedAIGuideLine {
    lastUpdate: number;
}

export interface GuideLineProps {
    tone: string;
    atmosphere: string;
    writingStyle: string;
    themes: string;
    symbolism: string;
    motifs: string;
    narrativeVoice: string;
    pacing: string;
    intendedAudience: string;
    keyMessages: string;
}

export interface GuideLineAI {
    narrativeType: number | null;
    dialogueType: number | null;
    globalResume: string | null;
    atmosphere: string | null;
    verbeTense: number | null;
    langue: number | null;
    currentResume: string | null;
    themes: string | null;
}

export default class GuideLine {
    /**
     * Retrieves and decrypts the guideline for a specific book.
     * @param userId - The unique identifier of the user
     * @param bookId - The unique identifier of the book
     * @param lang - The language for error messages ('fr' or 'en'), defaults to 'fr'
     * @returns The decrypted guideline properties or null if not found
     */
    public static async getGuideLine(userId: string, bookId: string, lang: 'fr' | 'en' = 'fr'): Promise<GuideLineProps | null> {
        const guideLineResults: GuideLineQuery[] = GuidelineRepo.fetchGuideLine(userId, bookId, lang);
        if (guideLineResults.length === 0) {
            return null;
        }
        const guideLineData: GuideLineQuery = guideLineResults[0];
        const encryptionKey: string = getUserEncryptionKey(userId);
        return {
            tone: guideLineData.tone ? System.decryptDataWithUserKey(guideLineData.tone, encryptionKey) : '',
            atmosphere: guideLineData.atmosphere ? System.decryptDataWithUserKey(guideLineData.atmosphere, encryptionKey) : '',
            writingStyle: guideLineData.writing_style ? System.decryptDataWithUserKey(guideLineData.writing_style, encryptionKey) : '',
            themes: guideLineData.themes ? System.decryptDataWithUserKey(guideLineData.themes, encryptionKey) : '',
            symbolism: guideLineData.symbolism ? System.decryptDataWithUserKey(guideLineData.symbolism, encryptionKey) : '',
            motifs: guideLineData.motifs ? System.decryptDataWithUserKey(guideLineData.motifs, encryptionKey) : '',
            narrativeVoice: guideLineData.narrative_voice ? System.decryptDataWithUserKey(guideLineData.narrative_voice, encryptionKey) : '',
            pacing: guideLineData.pacing ? System.decryptDataWithUserKey(guideLineData.pacing, encryptionKey) : '',
            intendedAudience: guideLineData.intended_audience ? System.decryptDataWithUserKey(guideLineData.intended_audience, encryptionKey) : '',
            keyMessages: guideLineData.key_messages ? System.decryptDataWithUserKey(guideLineData.key_messages, encryptionKey) : '',
        };
    }

    /**
     * Updates or creates a guideline for a specific book with encrypted data.
     * @param userId - The unique identifier of the user
     * @param bookId - The unique identifier of the book
     * @param tone - The tone setting for the book (nullable)
     * @param atmosphere - The atmosphere setting for the book (nullable)
     * @param writingStyle - The writing style for the book (nullable)
     * @param themes - The themes for the book (nullable)
     * @param symbolism - The symbolism elements for the book (nullable)
     * @param motifs - The motifs for the book (nullable)
     * @param narrativeVoice - The narrative voice for the book (nullable)
     * @param pacing - The pacing setting for the book (nullable)
     * @param keyMessages - The key messages for the book (nullable)
     * @param intendedAudience - The intended audience for the book (nullable)
     * @param lang - The language for error messages ('fr' or 'en'), defaults to 'fr'
     * @returns True if the update was successful, false otherwise
     */
    public static async updateGuideLine(
        userId: string,
        bookId: string,
        tone: string | null,
        atmosphere: string | null,
        writingStyle: string | null,
        themes: string | null,
        symbolism: string | null,
        motifs: string | null,
        narrativeVoice: string | null,
        pacing: string | null,
        keyMessages: string | null,
        intendedAudience: string | null,
        lang: 'fr' | 'en' = 'fr'
    ): Promise<boolean> {
        const encryptionKey: string = getUserEncryptionKey(userId);
        const encryptedTone: string = tone ? System.encryptDataWithUserKey(tone, encryptionKey) : '';
        const encryptedAtmosphere: string = atmosphere ? System.encryptDataWithUserKey(atmosphere, encryptionKey) : '';
        const encryptedWritingStyle: string = writingStyle ? System.encryptDataWithUserKey(writingStyle, encryptionKey) : '';
        const encryptedThemes: string = themes ? System.encryptDataWithUserKey(themes, encryptionKey) : '';
        const encryptedSymbolism: string = symbolism ? System.encryptDataWithUserKey(symbolism, encryptionKey) : '';
        const encryptedMotifs: string = motifs ? System.encryptDataWithUserKey(motifs, encryptionKey) : '';
        const encryptedNarrativeVoice: string = narrativeVoice ? System.encryptDataWithUserKey(narrativeVoice, encryptionKey) : '';
        const encryptedPacing: string = pacing ? System.encryptDataWithUserKey(pacing, encryptionKey) : '';
        const encryptedKeyMessages: string = keyMessages ? System.encryptDataWithUserKey(keyMessages, encryptionKey) : '';
        const encryptedIntendedAudience: string = intendedAudience ? System.encryptDataWithUserKey(intendedAudience, encryptionKey) : '';

        return GuidelineRepo.updateGuideLine(
            userId,
            bookId,
            encryptedTone,
            encryptedAtmosphere,
            encryptedWritingStyle,
            encryptedThemes,
            encryptedSymbolism,
            encryptedMotifs,
            encryptedNarrativeVoice,
            encryptedPacing,
            encryptedKeyMessages,
            encryptedIntendedAudience,
            System.timeStampInSeconds(),
            lang
        );
    }

    /**
     * Retrieves and decrypts the AI guideline for a specific book.
     * @param userId - The unique identifier of the user
     * @param bookId - The unique identifier of the book
     * @param lang - The language for error messages ('fr' or 'en'), defaults to 'fr'
     * @returns The decrypted AI guideline data with default values if not found
     * @throws Error if an unexpected error occurs during retrieval
     */
    static getGuideLineAI(userId: string, bookId: string, lang: 'fr' | 'en' = 'fr'): GuideLineAI {
        const encryptionKey: string = getUserEncryptionKey(userId);
        try {
            const aiGuideLineData: GuideLineAIQuery = GuidelineRepo.fetchGuideLineAI(userId, bookId, lang);
            return {
                narrativeType: aiGuideLineData.narrative_type,
                dialogueType: aiGuideLineData.dialogue_type,
                globalResume: aiGuideLineData.global_resume ? System.decryptDataWithUserKey(aiGuideLineData.global_resume, encryptionKey) : '',
                atmosphere: aiGuideLineData.atmosphere ? System.decryptDataWithUserKey(aiGuideLineData.atmosphere, encryptionKey) : '',
                verbeTense: aiGuideLineData.verbe_tense,
                themes: aiGuideLineData.themes ? System.decryptDataWithUserKey(aiGuideLineData.themes, encryptionKey) : '',
                currentResume: aiGuideLineData.current_resume ? System.decryptDataWithUserKey(aiGuideLineData.current_resume, encryptionKey) : '',
                langue: aiGuideLineData.langue
            };
        } catch (error: unknown) {
            if (error instanceof Error && error.message.includes('not found')) {
                return {
                    narrativeType: 0,
                    dialogueType: 0,
                    globalResume: '',
                    atmosphere: '',
                    verbeTense: 0,
                    themes: '',
                    currentResume: '',
                    langue: 0
                };
            }
            if (error instanceof Error) {
                throw new Error(error.message);
            } else {
                const errorMessage: string = lang === 'fr'
                    ? "Erreur inconnue lors de la recuperation de la ligne directrice de l'IA."
                    : "Unknown error while fetching AI guideline.";
                throw new Error(errorMessage);
            }
        }
    }

    /**
     * Creates or updates an AI guideline for a specific book with encrypted data.
     * @param userId - The unique identifier of the user
     * @param bookId - The unique identifier of the book
     * @param narrativeType - The narrative type identifier
     * @param dialogueType - The dialogue type identifier
     * @param plotSummary - The plot summary text to be encrypted
     * @param toneAtmosphere - The tone and atmosphere description to be encrypted
     * @param verbTense - The verb tense identifier
     * @param language - The language identifier
     * @param themes - The themes description to be encrypted
     * @param lang - The language for error messages ('fr' or 'en'), defaults to 'fr'
     * @returns True if the operation was successful, false otherwise
     */
    public static setAIGuideLine(
        userId: string,
        bookId: string,
        narrativeType: number,
        dialogueType: number,
        plotSummary: string,
        toneAtmosphere: string,
        verbTense: number,
        language: number,
        themes: string,
        lang: 'fr' | 'en' = 'fr'
    ): boolean {
        const encryptionKey: string = getUserEncryptionKey(userId);
        const encryptedPlotSummary: string = plotSummary ? System.encryptDataWithUserKey(plotSummary, encryptionKey) : '';
        const encryptedToneAtmosphere: string = toneAtmosphere ? System.encryptDataWithUserKey(toneAtmosphere, encryptionKey) : '';
        const encryptedThemes: string = themes ? System.encryptDataWithUserKey(themes, encryptionKey) : '';
        return GuidelineRepo.insertAIGuideLine(
            userId,
            bookId,
            narrativeType,
            dialogueType,
            encryptedPlotSummary,
            encryptedToneAtmosphere,
            verbTense,
            language,
            encryptedThemes,
            System.timeStampInSeconds(),
            lang
        );
    }
}
