import StarterKit from '@tiptap/starter-kit'
import TextAlign from '@tiptap/extension-text-align'
import ChapterRepo, {
    ActChapterQuery,
    ChapterQueryResult,
    ChapterContentQueryResult,
    LastChapterResult,
    CompanionContentQueryResult,
    ChapterStoryQueryResult,
    ContentQueryResult
} from "@/electron/database/repositories/chapter.repository";
import System from "../System";
import {getUserEncryptionKey} from "../keyManager";
import { generateHTML } from "@tiptap/react";

export interface ChapterContent {
    version: number;
    content: string;
    wordsCount: number;
}

export interface ChapterContentData extends ChapterContent {
    title: string;
    chapterOrder: number;
}

export interface ChapterProps {
    chapterId: string;
    title: string;
    chapterOrder: number;
    chapterContent?: ChapterContent
}

export interface ActChapter {
    chapterInfoId: number;
    chapterId: string;
    title: string;
    chapterOrder: number;
    actId: number;
    incidentId: string | null;
    plotPointId: string | null;
    summary: string;
    goal: string;
}

export interface CompanionContent {
    version: number;
    content: string;
    wordsCount: number;
}

export interface ActStory {
    actId: number;
    summary: string;
    chapterSummary: string;
    chapterGoal: string;
    incidents: IncidentStory[];
    plotPoints: PlotPointStory[];
}

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

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

export default class Chapter {
    public static getAllChaptersFromABook(userId: string, bookId: string, lang: 'fr' | 'en' = 'fr'): ChapterProps[] {
        const chapters: ChapterQueryResult[] = ChapterRepo.fetchAllChapterFromABook(userId, bookId, lang);
        let returnChapters: ChapterProps[] = [];
        const userKey: string = getUserEncryptionKey(userId);
        for (const chapter of chapters) {
            const title: string = System.decryptDataWithUserKey(chapter.title, userKey);
            returnChapters.push({
                chapterId: chapter.chapter_id,
                title: title,
                chapterOrder: chapter.chapter_order
            });
        }
        return returnChapters;
    }

    public static getAllChapterFromActs(userId: string, bookId: string, lang: 'fr' | 'en' = 'fr'): ActChapter[] {
        const query: ActChapterQuery[] = ChapterRepo.fetchAllChapterForActs(userId, bookId, lang);
        let chapters: ActChapter[] = [];
        let tempChapter: { id: string, title: string }[] = []
        const userKey: string = getUserEncryptionKey(userId);
        if (query.length > 0) {
            for (const chapter of query) {
                let decryptTitle: string = '';
                const newTitleId: number = tempChapter.findIndex((temp: { id: string, title: string }) => temp.id === chapter.chapter_id);
                if (newTitleId > -1) {
                    decryptTitle = tempChapter[newTitleId]?.title ?? ''
                } else {
                    decryptTitle = System.decryptDataWithUserKey(chapter.title, userKey);
                    tempChapter.push({id: chapter.chapter_id, title: decryptTitle});
                }
                chapters.push({
                    chapterId: chapter.chapter_id,
                    title: decryptTitle,
                    actId: chapter.act_id,
                    chapterInfoId: chapter.chapter_info_id,
                    chapterOrder: chapter.chapter_order,
                    goal: chapter.goal ? System.decryptDataWithUserKey(chapter.goal, userKey) : '',
                    summary: chapter.summary ? System.decryptDataWithUserKey(chapter.summary, userKey) : '',
                    incidentId: chapter.incident_id,
                    plotPointId: chapter.plot_point_id
                })
            }
            return chapters;
        } else {
            return []
        }
    }

    public static getWholeChapter(userId: string, chapterId: string, version: number, bookId?: string, lang: 'fr' | 'en' = 'fr'): ChapterProps {
        const chapter: ChapterContentQueryResult = ChapterRepo.fetchWholeChapter(userId, chapterId, version, lang);
        const userKey: string = getUserEncryptionKey(userId);

        if (bookId) {
            ChapterRepo.updateLastChapterRecord(userId, bookId, chapterId, version, lang);
        }
        return {
            chapterId: chapter.chapter_id,
            title: System.decryptDataWithUserKey(chapter.title, userKey),
            chapterOrder: chapter.chapter_order,
            chapterContent: {
                content: chapter.content ? System.decryptDataWithUserKey(chapter.content, userKey) : '',
                version: version,
                wordsCount: chapter.words_count
            }
        };
    }

    public static saveChapterContent(userId: string, chapterId: string, version: number, content: JSON, wordsCount: number, currentTime: number, lang: 'fr' | 'en' = 'fr'): boolean {
        const userKey: string = getUserEncryptionKey(userId);
        const encryptContent: string = System.encryptDataWithUserKey(JSON.stringify(content), userKey);
        /*if (version === 2){
            const QS = new AI();
            const prompt:string = System.htmlToText(Chapter.tipTapToHtml(content));
            const response:string = await QS.request(prompt,'summary-chapter');
            console.log(response);
        }*/
        return ChapterRepo.updateChapterContent(userId, chapterId, version, encryptContent, wordsCount, lang);
    }

    public static getLastChapter(userId: string, bookId: string, lang: 'fr' | 'en' = 'fr'): ChapterProps | null {
        const lastChapter: LastChapterResult | null = ChapterRepo.fetchLastChapter(userId, bookId, lang);
        if (lastChapter) {
            return Chapter.getWholeChapter(userId, lastChapter.chapter_id, lastChapter.version, bookId, lang);
        }
        const chapter: ChapterContentQueryResult[] = ChapterRepo.fetchLastChapterContent(userId, bookId, lang);
        if (chapter.length === 0) {
            return null
        }
        const chapterData: ChapterContentQueryResult = chapter[0];
        const userKey: string = getUserEncryptionKey(userId);
        return {
            chapterId: chapterData.chapter_id,
            title: chapterData.title ? System.decryptDataWithUserKey(chapterData.title, userKey) : '',
            chapterOrder: chapterData.chapter_order,
            chapterContent: {
                content: chapterData.content ? System.decryptDataWithUserKey(chapterData.content, userKey) : '',
                version: chapterData.version,
                wordsCount: chapterData.words_count
            }
        };
    }

    public static addChapter(userId: string, bookId: string, title: string, wordsCount: number, chapterOrder: number, lang: 'fr' | 'en' = 'fr'): string {
        const hashedTitle: string = System.hashElement(title);
        const userKey: string = getUserEncryptionKey(userId);
        const encryptedTitle: string = System.encryptDataWithUserKey(title, userKey);

        if (ChapterRepo.checkNameDuplication(userId, bookId, hashedTitle, lang)) {
            throw new Error(lang === 'fr' ? `Ce nom de chapitre existe déjà.` : `This chapter name already exists.`);
        }
        const chapterId: string = System.createUniqueId();
        return ChapterRepo.insertChapter(chapterId, userId, bookId, encryptedTitle, hashedTitle, wordsCount, chapterOrder, lang);
    }

    public static removeChapter(userId: string, chapterId: string, lang: 'fr' | 'en' = 'fr'): boolean {
        return ChapterRepo.deleteChapter(userId, chapterId, lang);
    }

    public static addChapterInformation(userId: string, chapterId: string, actId: number, bookId: string, plotId: string | null, incidentId: string | null, lang: 'fr' | 'en' = 'fr'): string {
        const chapterInfoId: string = System.createUniqueId();
        return ChapterRepo.insertChapterInformation(chapterInfoId, userId, chapterId, actId, bookId, plotId, incidentId, lang);
    }

    public static updateChapter(userId: string, chapterId: string, title: string, chapterOrder: number, lang: 'fr' | 'en' = 'fr'): boolean {
        const hashedTitle: string = System.hashElement(title);
        const userKey: string = getUserEncryptionKey(userId);
        const encryptedTitle: string = System.encryptDataWithUserKey(title, userKey);
        return ChapterRepo.updateChapter(userId, chapterId, encryptedTitle, hashedTitle, chapterOrder, lang);
    }

    static updateChapterInfos(chapters: ActChapter[], userId: string, actId: number, bookId: string, incidentId: string | null, plotId: string | null, meta: string, lang: 'fr' | 'en' = 'fr') {
        const userKey: string = getUserEncryptionKey(userId);
        for (const chapter of chapters) {
            const summary: string = chapter.summary ? System.encryptDataWithUserKey(chapter.summary, userKey) : '';
            const goal: string = chapter.goal ? System.encryptDataWithUserKey(chapter.goal, userKey) : '';
            const chapterId: string = chapter.chapterId;
            ChapterRepo.updateChapterInfos(userId, chapterId, actId, bookId, incidentId, plotId, summary, goal, meta, lang);
        }
    }

    static getCompanionContent(userId: string, chapterId: string, version: number, lang: 'fr' | 'en' = 'fr'): CompanionContent {
        const versionNum: number = version - 1;
        const chapterResponse: CompanionContentQueryResult[] = ChapterRepo.fetchCompanionContent(userId, chapterId, versionNum, lang);
        if (chapterResponse.length === 0) {
            return {
                version: version,
                content: '',
                wordsCount: 0
            };
        }
        const chapter: CompanionContentQueryResult = chapterResponse[0];
        const userKey: string = getUserEncryptionKey(userId);
        return {
            version: chapter.version,
            content: chapter.content ? System.decryptDataWithUserKey(chapter.content, userKey) : '',
            wordsCount: chapter.words_count
        };
    }

    static getChapterStory(userId: string, chapterId: string, lang: 'fr' | 'en' = 'fr'): ActStory[] {
        const stories: ChapterStoryQueryResult[] = ChapterRepo.fetchChapterStory(userId, chapterId, lang);
        const actStories: Record<number, ActStory> = {};
        const userKey: string = getUserEncryptionKey(userId);

        for (const story of stories) {
            const actId: number = story.act_id;

            if (!actStories[actId]) {
                actStories[actId] = {
                    actId: actId,
                    summary: story.summary ? System.decryptDataWithUserKey(story.summary, userKey) : '',
                    chapterSummary: story.chapter_summary ? System.decryptDataWithUserKey(story.chapter_summary, userKey) : '',
                    chapterGoal: story.chapter_goal ? System.decryptDataWithUserKey(story.chapter_goal, userKey) : '',
                    incidents: [],
                    plotPoints: []
                };
            }

            if (story.incident_id) {
                const incidentTitle = story.incident_title ? System.decryptDataWithUserKey(story.incident_title, userKey) : '';
                const incidentSummary = story.incident_summary ? System.decryptDataWithUserKey(story.incident_summary, userKey) : '';

                const incidentExists = actStories[actId].incidents.some(
                    (incident) => incident.incidentTitle === incidentTitle && incident.incidentSummary === incidentSummary
                );

                if (!incidentExists) {
                    actStories[actId].incidents.push({
                        incidentTitle: incidentTitle,
                        incidentSummary: incidentSummary,
                        chapterSummary: story.chapter_summary ? System.decryptDataWithUserKey(story.chapter_summary, userKey) : '',
                        chapterGoal: story.chapter_goal ? System.decryptDataWithUserKey(story.chapter_goal, userKey) : ''
                    });
                }
            }

            if (story.plot_point_id) {
                const plotTitle = story.plot_title ? System.decryptDataWithUserKey(story.plot_title, userKey) : '';
                const plotSummary = story.plot_summary ? System.decryptDataWithUserKey(story.plot_summary, userKey) : '';

                const plotPointExists = actStories[actId].plotPoints.some(
                    (plotPoint) => plotPoint.plotTitle === plotTitle && plotPoint.plotSummary === plotSummary
                );

                if (!plotPointExists) {
                    actStories[actId].plotPoints.push({
                        plotTitle: plotTitle,
                        plotSummary: plotSummary,
                        chapterSummary: story.chapter_summary ? System.decryptDataWithUserKey(story.chapter_summary, userKey) : '',
                        chapterGoal: story.chapter_goal ? System.decryptDataWithUserKey(story.chapter_goal, userKey) : ''
                    });
                }
            }
        }

        return Object.values(actStories);
    }


    static getChapterContentByVersion(userId: string, chapterid: string, version: number, lang: 'fr' | 'en' = 'fr'): string {
        const chapter: ContentQueryResult = ChapterRepo.fetchChapterContentByVersion(userId, chapterid, version, lang);
        const userKey: string = getUserEncryptionKey(userId);
        return chapter.content ? System.decryptDataWithUserKey(chapter.content, userKey) : '';
    }

    static removeChapterInformation(userId: string, chapterInfoId: string, lang: 'fr' | 'en' = 'fr') {
        return ChapterRepo.deleteChapterInformation(userId, chapterInfoId, lang);
    }

    static tipTapToHtml(tipTapContent: JSON): string {
        const fixNode = (node: Record<string, unknown>): Record<string, unknown> => {
            if (!node) return node;

            if (node.type === 'text' && (!node.text || node.text === '')) {
                node.text = '\u00A0';
            }

            if (Array.isArray(node.content) && node.content.length) {
                node.content = node.content.map(fixNode);
            }

            return node;
        };

        return generateHTML(fixNode(tipTapContent as unknown as Record<string, unknown>), [
            StarterKit,
            TextAlign.configure({
                types: ['heading', 'paragraph'],
            }),
        ]);
    }
}
