import {ChapterListProps} from "@/lib/types/chapter";
import React, {useContext, useEffect, useRef, useState} from "react";
import {apiDelete, apiGet, apiPost} from '@/lib/api/client';
import {isDesktop} from '@/lib/configs';
import * as tauri from '@/lib/tauri';
import OfflineContext, {OfflineContextType} from '@/context/OfflineContext';
import {BooksSyncContext, BooksSyncContextProps} from '@/context/BooksSyncContext';
import {SyncedBook} from '@/lib/types/synced-book';
import {LocalSyncQueueContext, LocalSyncQueueContextProps} from '@/context/SyncQueueContext';
import {BookContext, BookContextProps} from "@/context/BookContext";
import {AlertContext, AlertContextProps} from "@/context/AlertContext";
import {ChapterContext, ChapterContextProps} from "@/context/ChapterContext";
import {SessionContext, SessionContextProps} from "@/context/SessionContext";
import {useRouter} from "@/lib/navigation";
import {FileText} from "lucide-react";
import ListItem from "@/components/ui/ListItem";
import AlertBox from "@/components/ui/AlertBox";
import {useTranslations} from '@/lib/i18n';
import InlineAddInput from "@/components/form/InlineAddInput";
import {LangContext, LangContextProps} from "@/context/LangContext";

export default function ScribeChapterComponent() {
    const t = useTranslations();
    const {lang}: LangContextProps = useContext<LangContextProps>(LangContext);
    
    const {book}: BookContextProps = useContext<BookContextProps>(BookContext);
    const {chapter}: ChapterContextProps = useContext<ChapterContextProps>(ChapterContext);
    const {errorMessage, successMessage}: AlertContextProps = useContext<AlertContextProps>(AlertContext);
    const {session}: SessionContextProps = useContext<SessionContextProps>(SessionContext);
    const userToken: string = session?.accessToken ? session?.accessToken : '';
    const {isCurrentlyOffline}: OfflineContextType = useContext<OfflineContextType>(OfflineContext);
    const {addToQueue}: LocalSyncQueueContextProps = useContext<LocalSyncQueueContextProps>(LocalSyncQueueContext);
    const {localSyncedBooks}: BooksSyncContextProps = useContext<BooksSyncContextProps>(BooksSyncContext);
    const router = useRouter();
    
    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: React.RefObject<Map<string, HTMLDivElement>> = useRef<Map<string, HTMLDivElement>>(new Map());
    const scrollContainerRef: React.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[];
            if (isDesktop && (isCurrentlyOffline() || book?.localBook)) {
                response = await tauri.getChapters(book?.bookId ?? '') as ChapterListProps[];
            } else {
                response = await apiGet<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"));
            }
        }
    }
    
    function navigateToChapter(chapterId: string): void {
        router.push(`/book/${book?.bookId}/chapter/${chapterId}`);
    }

    
    async function handleChapterUpdate(chapterId: string, title: string, chapterOrder: number): Promise<void> {
        try {
            let response: boolean;
            if (isDesktop && (isCurrentlyOffline() || book?.localBook)) {
                response = await tauri.updateChapter(chapterId, title, chapterOrder);
            } else {
                const updateData = {chapterId, chapterOrder, title};
                response = await apiPost<boolean>('chapter/update', updateData, userToken, lang);

                if (isDesktop && localSyncedBooks.find((sb: SyncedBook): boolean => sb.id === book?.bookId)) {
                    addToQueue('update_chapter', 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;
            if (isDesktop && (isCurrentlyOffline() || book?.localBook)) {
                response = await tauri.removeChapter(removeChapterId, book?.bookId ?? '', Date.now());
            } else {
                const deleteData = {bookId: book?.bookId, chapterId: removeChapterId};
                response = await apiDelete<boolean>('chapter/remove', deleteData, userToken, lang);

                if (isDesktop && localSyncedBooks.find((sb: SyncedBook): boolean => sb.id === book?.bookId)) {
                    addToQueue('remove_chapter', {...deleteData, deletedAt: Date.now()});
                }
            }
            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 ?? '');
        try {
            let chapterId: string;
            if (isDesktop && (isCurrentlyOffline() || book?.localBook)) {
                chapterId = await tauri.addChapter({
                    bookId: book?.bookId ?? '',
                    title: chapterTitle,
                    chapterOrder: chapterOrder,
                });
            } else {
                const addData = {bookId: book?.bookId, chapterOrder, title: chapterTitle};
                chapterId = await apiPost<string>('chapter/add', addData, userToken, lang);

                if (isDesktop && localSyncedBooks.find((sb: SyncedBook): boolean => sb.id === book?.bookId)) {
                    addToQueue('add_chapter', addData);
                }
            }
            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]
            })
            navigateToChapter(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">
                <h3 className="text-sm font-semibold text-text-secondary uppercase tracking-wider mb-3">{t("scribeChapterComponent.sheetHeading")}</h3>
                <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): React.JSX.Element => (
                            <div key={chap.chapterId}
                                 ref={(el: HTMLDivElement | null): void => {
                                     if (el) {
                                         chapterRefs.current.set(chap.chapterId, el);
                                     } else {
                                         chapterRefs.current.delete(chap.chapterId);
                                     }
                                 }}>
                                <ListItem icon={FileText}
                                          onClick={(): void => navigateToChapter(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 rounded-xl hover:bg-tertiary cursor-pointer transition-colors duration-150">
                            <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">
                <h3 className="text-sm font-semibold text-text-secondary uppercase tracking-wider mb-3">{t("scribeChapterComponent.chaptersHeading")}</h3>
                <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): React.JSX.Element => (
                            <div key={chap.chapterId}
                                 ref={(el: HTMLDivElement | null): void => {
                                     if (el) {
                                         chapterRefs.current.set(chap.chapterId, el);
                                     } else {
                                         chapterRefs.current.delete(chap.chapterId);
                                     }
                                 }}>
                                <ListItem onClick={(): void => navigateToChapter(chap.chapterId)}
                                          isEditable={true}
                                          handleUpdate={handleChapterUpdate}
                                          handleDelete={handleDeleteConfirmation}
                                          selectedId={chapter?.chapterId ?? ''}
                                          id={chap.chapterId} text={chap.title}
                                          numericalIdentifier={chap.chapterOrder}
                                          onReorder={(chapterId: string, newOrder: number): void => {
                                              setChapters((previousChapters: ChapterListProps[]): ChapterListProps[] =>
                                                  previousChapters.map((chapter: ChapterListProps): ChapterListProps =>
                                                      chapter.chapterId === chapterId ? {
                                                          ...chapter,
                                                          chapterOrder: newOrder
                                                      } : chapter
                                                  )
                                              );
                                          }}/>
                            </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>
    )
}