import {ChapterListProps, ChapterProps} from "@/lib/models/Chapter";
import {RefObject, useContext, useEffect, useRef, useState} from "react";
import System from "@/lib/models/System";
import {BookContext} from "@/context/BookContext";
import {AlertContext} from "@/context/AlertContext";
import {ChapterContext} from "@/context/ChapterContext";
import {SessionContext} from "@/context/SessionContext";
import {faSheetPlastic} from "@fortawesome/free-solid-svg-icons";
import ListItem from "@/components/ListItem";
import AlertBox from "@/components/AlertBox";
import {useTranslations} from "next-intl";
import InlineAddInput from "@/components/form/InlineAddInput";
import {LangContext} from "@/context/LangContext";
import OfflineContext, {OfflineContextType} from "@/context/OfflineContext";
import {LocalSyncQueueContext, LocalSyncQueueContextProps} from "@/context/SyncQueueContext";
import {BooksSyncContext, BooksSyncContextProps} from "@/context/BooksSyncContext";
import {SyncedBook} from "@/lib/models/SyncedBook";

export default function ScribeChapterComponent() {
    const t = useTranslations();
    const {lang} = useContext(LangContext);
    const {isCurrentlyOffline} = useContext<OfflineContextType>(OfflineContext);
    const {addToQueue} = useContext<LocalSyncQueueContextProps>(LocalSyncQueueContext);
    const {localSyncedBooks} = useContext<BooksSyncContextProps>(BooksSyncContext);

    const {book} = useContext(BookContext);
    const {chapter, setChapter} = useContext(ChapterContext);
    const {errorMessage, successMessage} = useContext(AlertContext);
    const {session} = useContext(SessionContext);
    const userToken: string = session?.accessToken ? session?.accessToken : '';
    
    const [chapters, setChapters] = useState<ChapterListProps[]>([])
    
    const [newChapterName, setNewChapterName] = useState<string>('');
    const [newChapterOrder, setNewChapterOrder] = useState<number>(1);

    const [deleteConfirmationMessage, setDeleteConfirmationMessage] = useState<boolean>(false);
    const [removeChapterId, setRemoveChapterId] = useState<string>('');
    
    const chapterRefs: RefObject<Map<string, HTMLDivElement>> = useRef<Map<string, HTMLDivElement>>(new Map());
    const scrollContainerRef: RefObject<HTMLUListElement | null> = useRef<HTMLUListElement>(null);
    
    useEffect((): void => {
        if (book)
        getChapterList().then();
    }, [book]);
    
    useEffect((): void => {
        setNewChapterOrder(getNextChapterOrder());
    }, [chapters]);
    
    useEffect((): void => {
        if (chapter?.chapterId && scrollContainerRef.current) {
            setTimeout(():void => {
                const element: HTMLDivElement | undefined = chapterRefs.current.get(chapter.chapterId);
                const container: HTMLUListElement | null = scrollContainerRef.current;
                
                if (element && container) {
                    const containerRect:DOMRect = container.getBoundingClientRect();
                    const elementRect:DOMRect = element.getBoundingClientRect();
                    
                    const relativeTop:number = elementRect.top - containerRect.top + container.scrollTop;
                    const scrollPosition:number = relativeTop - (containerRect.height / 2) + (elementRect.height / 2);
                    
                    container.scrollTo({
                        top: Math.max(0, scrollPosition),
                        behavior: 'smooth'
                    });
                }
            }, 100);
        }
    }, [chapter?.chapterId]);
    
    function getNextChapterOrder(): number {
        const maxOrder: number = Math.max(0, ...chapters.map((chap: ChapterListProps) => chap.chapterOrder ?? 0));
        return maxOrder + 1;
    }
    
    async function getChapterList(): Promise<void> {
        try {
            let response: ChapterListProps[]|null;
            if (isCurrentlyOffline()){
                response = await window.electron.invoke<ChapterListProps[]>('db:book:chapters', book?.bookId)
            } else {
                if (book?.localBook){
                    response = await window.electron.invoke<ChapterListProps[]>('db:book:chapters', book?.bookId)
                } else {
                    response = await System.authGetQueryToServer<ChapterListProps[]>(`book/chapters?id=${book?.bookId}`, userToken, lang);
                }
            }
            if (response) {
                setChapters(response);
            }
        } catch (e: unknown) {
            if (e instanceof Error) {
                errorMessage(e.message);
            } else {
                errorMessage(t("scribeChapterComponent.errorFetchChapters"));
            }
        }
    }
    
    async function getChapter(chapterId: string): Promise<void> {
        const version: number = chapter?.chapterContent.version ? chapter?.chapterContent.version : 2;
        try {
            let response: ChapterProps | null
            if (isCurrentlyOffline()) {
                response = await window.electron.invoke<ChapterProps>('db:chapter:whole', {
                    bookid: book?.bookId,
                    id: chapterId,
                    version: version,
                })
            } else {
                if (book?.localBook){
                    response = await window.electron.invoke<ChapterProps>('db:chapter:whole', {
                        bookid: book?.bookId,
                        id: chapterId,
                        version: version,
                    })
                } else {
                    response = await System.authGetQueryToServer<ChapterProps>(`chapter/whole`, userToken, lang, {
                        bookid: book?.bookId,
                        id: chapterId,
                        version: version,
                    });
                }
            }
            if (!response) {
                errorMessage(t("scribeChapterComponent.errorFetchChapter"));
                return;
            }
            setChapter(response);
        } catch (e: unknown) {
            if (e instanceof Error) {
                errorMessage(e.message);
            } else {
                errorMessage(t("scribeChapterComponent.errorFetchChapter"));
            }
        }
    }
    
    async function handleChapterUpdate(chapterId: string, title: string, chapterOrder: number): Promise<void> {
        try {
            let response: boolean;
            const updateData = {
                chapterId: chapterId,
                chapterOrder: chapterOrder,
                title: title,
            };
            if (isCurrentlyOffline() || book?.localBook) {
                response = await window.electron.invoke<boolean>('db:chapter:update', updateData);
            } else {
                response = await System.authPostToServer<boolean>('chapter/update', updateData, userToken, lang);

                if (localSyncedBooks.find((syncedBook: SyncedBook): boolean => syncedBook.id === book?.bookId)) {
                    addToQueue('db:chapter:update', updateData);
                }
            }
            if (!response) {
                errorMessage(t("scribeChapterComponent.errorChapterUpdate"));
                return;
            }
            successMessage(t("scribeChapterComponent.successUpdate"));
            setChapters((prevState: ChapterListProps[]): ChapterListProps[] => {
                return prevState.map((chapter: ChapterListProps): ChapterListProps => {
                    if (chapter.chapterId === chapterId) {
                        chapter.chapterOrder = chapterOrder;
                        chapter.title = title;
                    }
                    return chapter;
                });
            });
        } catch (e: unknown) {
            if (e instanceof Error) {
                errorMessage(t("scribeChapterComponent.errorChapterUpdateFr"));
            } else {
                errorMessage(t("scribeChapterComponent.errorChapterUpdateEn"));
            }
        }
    }
    
    async function handleDeleteConfirmation(chapterId: string): Promise<void> {
        setDeleteConfirmationMessage(true);
        setRemoveChapterId(chapterId);
    }
    
    async function handleDeleteChapter(): Promise<void> {
        try {
            setDeleteConfirmationMessage(false);
            let response:boolean = false;
            const deletedAt: number = System.timeStampInSeconds();
            if (isCurrentlyOffline() || book?.localBook) {
                response = await window.electron.invoke<boolean>('db:chapter:remove', {
                    chapterId: removeChapterId,
                    bookId: book?.bookId,
                    deletedAt,
                });
            } else {
                response = await System.authDeleteToServer<boolean>('chapter/remove', {
                    chapterId: removeChapterId,
                    bookId: book?.bookId,
                    deletedAt,
                }, userToken, lang);

                if (localSyncedBooks.find((syncedBook: SyncedBook): boolean => syncedBook.id === book?.bookId)) {
                    addToQueue('db:chapter:remove', {
                        chapterId: removeChapterId,
                        bookId: book?.bookId,
                        deletedAt,
                    });
                }
            }
            if (!response) {
                errorMessage(t("scribeChapterComponent.errorChapterDelete"));
                return;
            }
            const updatedChapters: ChapterListProps[] = chapters.filter(
                (chapter: ChapterListProps): boolean => chapter.chapterId !== removeChapterId,
            );
            setChapters(updatedChapters);
        } catch (e: unknown) {
            if (e instanceof Error) {
                errorMessage(e.message);
            } else {
                errorMessage(t("scribeChapterComponent.unknownErrorChapterDelete"));
            }
        }
    }
    
    async function handleAddChapter(chapterOrder: number): Promise<void> {
        if (!newChapterName && chapterOrder >= 0) {
            errorMessage(t("scribeChapterComponent.errorChapterNameRequired"));
            return;
        }
        const chapterTitle: string = chapterOrder >= 0 ? newChapterName : book?.title as string;
        try {
            let chapterId:string|null = null;
            const addData = {
                bookId: book?.bookId,
                chapterOrder: chapterOrder,
                title: chapterTitle
            };
            if (isCurrentlyOffline() || book?.localBook){
                chapterId = await window.electron.invoke<string>('db:chapter:add', addData);
            } else {
                chapterId = await System.authPostToServer<string>('chapter/add', addData, userToken, lang);

                if (localSyncedBooks.find((syncedBook: SyncedBook): boolean => syncedBook.id === book?.bookId)) {
                    addToQueue('db:chapter:add', {
                        ...addData,
                        chapterId,
                    });
                }
            }
            if (!chapterId) {
                errorMessage(t("scribeChapterComponent.errorChapterSubmit", {chapterName: newChapterName}));
                return;
            }
            const newChapter: ChapterListProps = {
                chapterId: chapterId,
                title: chapterTitle,
                chapterOrder: chapterOrder
            }
            setChapters((prevState: ChapterListProps[]): ChapterListProps[] => {
                return [newChapter, ...prevState]
            })
            await getChapter(chapterId);
        } catch (e: unknown) {
            if (e instanceof Error) {
                errorMessage(e.message);
            } else {
                errorMessage(t("scribeChapterComponent.errorChapterSubmit", {chapterName: newChapterName}));
            }
        }
    }
    
    return (
        <div className="flex-1 flex flex-col p-4 min-h-0">
            <div className="mb-4">
                <div className="flex items-center gap-2 mb-3">
                    <div className="h-6 w-1 bg-primary rounded-full"></div>
                    <h3 className="text-lg font-bold text-primary tracking-wide">{t("scribeChapterComponent.sheetHeading")}</h3>
                </div>
                <ul className="space-y-2">
                    {
                        chapters.filter((chap: ChapterListProps): boolean => {
                                return chap.chapterOrder !== undefined && chap.chapterOrder < 0;
                            })
                            .sort((a: ChapterListProps, b: ChapterListProps): number => {
                                const aOrder: number = a.chapterOrder ?? 0;
                                const bOrder: number = b.chapterOrder ?? 0;
                                return aOrder - bOrder;
                            }).map((chap: ChapterListProps) => (
                            <div key={chap.chapterId}
                                 ref={(el): void => {
                                     if (el) {
                                         chapterRefs.current.set(chap.chapterId, el);
                                     } else {
                                         chapterRefs.current.delete(chap.chapterId);
                                     }
                                 }}>
                                <ListItem icon={faSheetPlastic}
                                          onClick={(): Promise<void> => getChapter(chap.chapterId)}
                                          selectedId={chapter?.chapterId ?? ''}
                                          id={chap.chapterId}
                                          text={chap.title}/>
                            </div>
                        ))
                    }
                    {
                        chapters.filter((chap: ChapterListProps): boolean => {
                            return chap.chapterOrder !== undefined && chap.chapterOrder < 0;
                        }).length === 0 &&
                        <li onClick={(): Promise<void> => handleAddChapter(-1)}
                            className="group p-3 bg-secondary/30 rounded-xl hover:bg-secondary cursor-pointer transition-all hover:shadow-md border border-secondary/30 hover:border-primary/30">
                            <span
                                className="text-sm font-medium text-muted group-hover:text-text-primary transition-colors">
                                {t("scribeChapterComponent.createSheet")}
                            </span>
                        </li>
                    }
                </ul>
            </div>
            
            <div className="flex-1 flex flex-col mt-6 min-h-0">
                <div className="flex items-center gap-2 mb-3">
                    <div className="h-6 w-1 bg-primary rounded-full"></div>
                    <h3 className="text-lg font-bold text-primary tracking-wide">{t("scribeChapterComponent.chaptersHeading")}</h3>
                </div>
                <ul ref={scrollContainerRef} className="flex-1 space-y-2 overflow-y-auto pr-2 min-h-0">
                    {
                        chapters.filter((chap: ChapterListProps): boolean => {
                                return !(chap.chapterOrder && chap.chapterOrder < 0);
                            })
                            .sort((a: ChapterListProps, b: ChapterListProps): number => {
                                const aOrder: number = a.chapterOrder ?? 0;
                                const bOrder: number = b.chapterOrder ?? 0;
                                return aOrder - bOrder;
                            }).map((chap: ChapterListProps) => (
                            <div key={chap.chapterId}
                                 ref={(el): void => {
                                     if (el) {
                                         chapterRefs.current.set(chap.chapterId, el);
                                     } else {
                                         chapterRefs.current.delete(chap.chapterId);
                                     }
                                 }}>
                                <ListItem onClick={(): Promise<void> => getChapter(chap.chapterId)}
                                          isEditable={true}
                                          handleUpdate={handleChapterUpdate}
                                          handleDelete={handleDeleteConfirmation}
                                          selectedId={chapter?.chapterId ?? ''}
                                          id={chap.chapterId} text={chap.title}
                                          numericalIdentifier={chap.chapterOrder}/>
                            </div>
                        ))
                    }
                </ul>
                <div className="mt-2 shrink-0">
                    <InlineAddInput
                        value={newChapterName}
                        setValue={setNewChapterName}
                        numericalValue={newChapterOrder}
                        setNumericalValue={setNewChapterOrder}
                        placeholder={t("scribeChapterComponent.addChapterPlaceholder")}
                        onAdd={async (): Promise<void> => {
                            await handleAddChapter(newChapterOrder);
                            setNewChapterName("");
                        }}
                        showNumericalInput={true}
                    />
                </div>
            </div>
            {
                deleteConfirmationMessage &&
                <AlertBox title={t("scribeChapterComponent.deleteChapterTitle")}
                          message={t("scribeChapterComponent.deleteChapterMessage")}
                          type={"danger"} onConfirm={(): Promise<void> => handleDeleteChapter()}
                          onCancel={(): void => setDeleteConfirmationMessage(false)}/>
            }
        </div>
    )
}