import {useContext, useEffect, useState} from "react";
import System from "@/lib/models/System";
import {AlertContext} from "@/context/AlertContext";
import {BookContext} from "@/context/BookContext";
import SearchBook from "./SearchBook";
import {FontAwesomeIcon} from "@fortawesome/react-fontawesome";
import {faBook, faDownload, faGear, faTrash} from "@fortawesome/free-solid-svg-icons";
import {SessionContext} from "@/context/SessionContext";
import Book, {BookListProps, BookProps} from "@/lib/models/Book";
import BookCard from "@/components/book/BookCard";
import BookCardSkeleton from "@/components/book/BookCardSkeleton";
import GuideTour, {GuideStep} from "@/components/GuideTour";
import User from "@/lib/models/User";
import {useTranslations} from "next-intl";
import {LangContext, LangContextProps} from "@/context/LangContext";
import OfflineContext, {OfflineContextType} from "@/context/OfflineContext";
import {BooksSyncContext, BooksSyncContextProps, SyncType} from "@/context/BooksSyncContext";
import {BookSyncCompare, SyncedBook} from "@/lib/models/SyncedBook";

export default function BookList() {
    const {session, setSession} = useContext(SessionContext);
    const accessToken: string = session?.accessToken || '';
    const {errorMessage} = useContext(AlertContext);
    const {setBook} = useContext(BookContext);
    const t = useTranslations();
    const {lang} = useContext<LangContextProps>(LangContext)
    const {isCurrentlyOffline} = useContext<OfflineContextType>(OfflineContext)
    const {booksToSyncFromServer, booksToSyncToServer, serverOnlyBooks, localOnlyBooks} = useContext<BooksSyncContextProps>(BooksSyncContext)
    
    const [searchQuery, setSearchQuery] = useState<string>('');
    const [groupedBooks, setGroupedBooks] = useState<Record<string, BookProps[]>>({});
    const [isLoadingBooks, setIsLoadingBooks] = useState<boolean>(true);

    const [bookGuide, setBookGuide] = useState<boolean>(false);
    
    const bookGuideSteps: GuideStep[] = [
        {
            id: 0,
            targetSelector: '[data-guide="book-category"]',
            position: 'left',
            highlightRadius: -200,
            title: `${t("bookList.guideStep0Title")} ${session.user?.name}`,
            content: (
                <div>
                    <p>{t("bookList.guideStep0Content")}</p>
                </div>
            ),
        },
        {
            id: 1,
            targetSelector: '[data-guide="book-card"]',
            position: 'left',
            title: t("bookList.guideStep1Title"),
            content: (
                <div>
                    <p>{t("bookList.guideStep1Content")}</p>
                </div>
            ),
        },
        {
            id: 2,
            targetSelector: '[data-guide="bottom-book-card"]',
            position: 'left',
            title: t("bookList.guideStep2Title"),
            content: (
                <div>
                    <p>
                        <FontAwesomeIcon icon={faGear} className="mr-2 text-primary w-5 h-5"/>
                        {t("bookList.guideStep2ContentGear")}
                    </p>
                    <p>
                        <FontAwesomeIcon icon={faDownload} className="mr-2 text-primary w-5 h-5"/>
                        {t("bookList.guideStep2ContentDownload")}
                    </p>
                    <p>
                        <FontAwesomeIcon icon={faTrash} className="mr-2 text-primary w-5 h-5"/>
                        {t("bookList.guideStep2ContentTrash")}
                    </p>
                </div>
            ),
        },
    ]
    
    useEffect((): void => {
        if (groupedBooks && Object.keys(groupedBooks).length > 0 && User.guideTourDone(session.user?.guideTour || [], 'new-first-book')) {
            setBookGuide(true);
        }
    }, [groupedBooks]);
    
    useEffect((): void => {
        getBooks().then()
    }, [booksToSyncFromServer, booksToSyncToServer, serverOnlyBooks, localOnlyBooks]);
    
    useEffect((): void => {
        if (accessToken) getBooks().then();
    }, [accessToken]);
    
    async function handleFirstBookGuide(): Promise<void> {
        try {
            const response: boolean = await System.authPostToServer<boolean>(
                'logs/tour',
                {plateforme: 'web', tour: 'new-first-book'},
                session.accessToken, lang
            );
            if (response) {
                setSession(User.setNewGuideTour(session, 'new-first-book'));
                setBookGuide(false);
            }
        } catch (e: unknown) {
            if (e instanceof Error) {
                errorMessage(e.message);
            } else {
                errorMessage(t("bookList.errorBookCreate"));
            }
        }
    }
    
    async function getBooks(): Promise<void> {
        setIsLoadingBooks(true);
        try {
            let bookResponse: (BookListProps & { itIsLocal: boolean })[] = [];
            if (!isCurrentlyOffline()) {
                const [onlineBooks, localBooks]: [BookListProps[], BookListProps[]] = await Promise.all([
                    System.authGetQueryToServer<BookListProps[]>('books', accessToken, lang),
                    window.electron.invoke<BookListProps[]>('db:book:books')
                ]);
                const onlineBookIds: Set<string> = new Set(onlineBooks.map((book: BookListProps): string => book.id));
                const uniqueLocalBooks: BookListProps[] = localBooks.filter((book: BookListProps): boolean => !onlineBookIds.has(book.id));
                bookResponse = [
                    ...onlineBooks.map((book: BookListProps): BookListProps & { itIsLocal: boolean } => ({ ...book, itIsLocal: false })),
                    ...uniqueLocalBooks.map((book: BookListProps): BookListProps & { itIsLocal: boolean } => ({ ...book, itIsLocal: true }))
                ];
            } else {
                const localBooks: BookListProps[] = await window.electron.invoke<BookListProps[]>('db:book:books');
                bookResponse = localBooks.map((book: BookListProps): BookListProps & { itIsLocal: boolean } => ({ ...book, itIsLocal: true }));
            }
            if (bookResponse) {
                const booksByType: Record<string, BookProps[]> = bookResponse.reduce((groups: Record<string, BookProps[]>, book: BookListProps): Record<string, BookProps[]> => {
                    const imageDataUrl: string = book.coverImage ? 'data:image/jpeg;base64,' + book.coverImage : '';
                    const categoryLabel: string = Book.getBookTypeLabel(book.type);
                    const transformedBook: BookProps = {
                        bookId: book.id,
                        type: categoryLabel,
                        title: book.title,
                        subTitle: book.subTitle,
                        summary: book.summary,
                        serie: book.serieId,
                        publicationDate: book.desiredReleaseDate,
                        desiredWordCount: book.desiredWordCount,
                        totalWordCount: 0,
                        coverImage: imageDataUrl,
                    };
                    if (!groups[t(categoryLabel)]) {
                        groups[t(categoryLabel)] = [];
                    }
                    groups[t(categoryLabel)].push(transformedBook);
                    return groups;
                }, {});
                setGroupedBooks(booksByType);
            }
        } catch (e: unknown) {
            if (e instanceof Error) {
                errorMessage(e.message);
            } else {
                errorMessage(t("bookList.errorBooksFetch"));
            }
        } finally {
            setIsLoadingBooks(false);
        }
    }
    
    const filteredGroupedBooks: Record<string, BookProps[]> = Object.entries(groupedBooks).reduce(
        (acc: Record<string, BookProps[]>, [category, books]: [string, BookProps[]]): Record<string, BookProps[]> => {
            const filteredBooks: BookProps[] = books.filter((book: BookProps): boolean =>
                book.title.toLowerCase().includes(searchQuery.toLowerCase())
            );
            
            if (filteredBooks.length > 0) {
                acc[category] = filteredBooks;
            }
            return acc;
        },
        {}
    );
    
    function detectBookSyncStatus(bookId: string):SyncType {
        if (serverOnlyBooks.find((book: SyncedBook):boolean => book.id === bookId)) {
            return 'server-only';
        }
        if (localOnlyBooks.find((book: SyncedBook):boolean => book.id === bookId)) {
            return 'local-only';
        }
        if (booksToSyncFromServer.find((book: BookSyncCompare):boolean => book.id === bookId)) {
            return 'to-sync-from-server';
        }
        if (booksToSyncToServer.find((book: BookSyncCompare):boolean => book.id === bookId)) {
            return 'to-sync-to-server';
        }
        return 'synced';
    }
    
    async function getBook(bookId: string): Promise<void> {
        try {
            let bookResponse: BookListProps|null = null;
            if (isCurrentlyOffline()){
                bookResponse = await window.electron.invoke('db:book:bookBasicInformation', bookId)
            } else {
                bookResponse = await System.authGetQueryToServer<BookListProps>(`book/basic-information`, accessToken, lang, {
                    id: bookId
                });
            }
            if (!bookResponse) {
                errorMessage(t("bookList.errorBookDetails"));
                return;
            }
            if (setBook) {
                setBook({
                    bookId: bookId,
                    title: bookResponse?.title || '',
                    subTitle: bookResponse?.subTitle || '',
                    summary: bookResponse?.summary || '',
                    type: bookResponse?.type || '',
                    serie: bookResponse?.serieId,
                    publicationDate: bookResponse?.desiredReleaseDate || '',
                    desiredWordCount: bookResponse?.desiredWordCount || 0,
                    totalWordCount: 0,
                    coverImage: bookResponse?.coverImage ? 'data:image/jpeg;base64,' + bookResponse.coverImage : '',
                });
            }
        } catch (e: unknown) {
            if (e instanceof Error) {
                errorMessage(e.message);
            } else {
                errorMessage(t("bookList.errorUnknown"));
            }
        }
    }
    
    return (
        <div
            className="flex flex-col items-center h-full overflow-hidden w-full text-text-primary font-['Lora']">
            {session?.user && (
                <div data-guide="search-bar" className="w-full max-w-3xl px-4 pt-6 pb-4">
                    <SearchBook searchQuery={searchQuery} setSearchQuery={setSearchQuery}/>
                </div>
            )}
            <div className="flex flex-col w-full overflow-y-auto h-full min-h-0 flex-grow">
                {
                    isLoadingBooks ? (
                        <>
                            <div className="text-center mb-8 px-6">
                                <h1 className="font-['ADLaM_Display'] text-4xl mb-3 text-text-primary">{t("bookList.library")}</h1>
                                <p className="text-muted italic text-lg">{t("bookList.booksAreMirrors")}</p>
                            </div>

                            <div className="w-full mb-10">
                                <div className="flex justify-between items-center w-full max-w-5xl mx-auto mb-4 px-6">
                                    <div className="h-8 bg-secondary/30 rounded-xl w-32 animate-pulse"></div>
                                    <div className="h-6 bg-secondary/20 rounded-lg w-24 animate-pulse"></div>
                                </div>
                                
                                <div className="flex flex-wrap justify-center items-start w-full px-4">
                                    {Array.from({length: 6}).map((_, id: number) => (
                                        <div key={id}
                                             className="w-full sm:w-1/3 md:w-1/4 lg:w-1/5 xl:w-1/6 p-2 box-border">
                                            <BookCardSkeleton/>
                                        </div>
                                    ))}
                                </div>
                            </div>
                        </>
                    ) : Object.entries(filteredGroupedBooks).length > 0 ? (
                        <>
                            <div className="text-center mb-8 px-6">
                                <h1 className="font-['ADLaM_Display'] text-4xl mb-3 text-text-primary">{t("bookList.library")}</h1>
                                <p className="text-muted italic text-lg">{t("bookList.booksAreMirrors")}</p>
                            </div>
                            
                            {Object.entries(filteredGroupedBooks).map(([category, books], index) => (
                                <div {...(index === 0 && {'data-guide': 'book-category'})} key={category}
                                     className="w-full mb-10">
                                    <div
                                        className="flex justify-between items-center w-full max-w-5xl mx-auto mb-6 px-6">
                                        <h2 className="text-3xl text-text-primary capitalize font-['ADLaM_Display'] flex items-center gap-3">
                                            <span className="w-1 h-8 bg-primary rounded-full"></span>
                                            <span>{category}</span>
                                        </h2>
                                        <span
                                            className="text-muted text-lg font-medium bg-secondary/30 px-4 py-1.5 rounded-full">{books.length} {t("bookList.works")}</span>
                                    </div>
                                    
                                    <div className="flex flex-wrap justify-center items-start w-full px-4">
                                        {
                                            books.map((book: BookProps, idx) => (
                                                <div key={book.bookId || `book-${idx}`}
                                                     {...(idx === 0 && {'data-guide': 'book-card'})}
                                                     className={`w-full sm:w-1/3 md:w-1/4 lg:w-1/5 xl:w-1/6 p-2 box-border ${User.guideTourDone(session.user?.guideTour || [], 'new-first-book') && 'mb-[200px]'}`}>
                                                    <BookCard book={book}
                                                                syncStatus={detectBookSyncStatus(book.bookId)}
                                                              onClickCallback={getBook}
                                                              index={idx}
                                                    />
                                                </div>
                                            ))
                                        }
                                    </div>
                                </div>
                            ))}
                        </>
                    ) : (
                        <div className="flex items-center justify-center h-full">
                            <div className="text-center p-8 max-w-lg">
                                <div
                                    className="w-24 h-24 bg-primary/20 text-primary rounded-2xl flex items-center justify-center mx-auto mb-6 shadow-lg animate-pulse">
                                    <FontAwesomeIcon icon={faBook} className={'w-12 h-12'}/>
                                </div>
                                <h2 className="text-4xl font-['ADLaM_Display'] mb-4 text-text-primary">{t("bookList.welcomeWritingWorkshop")}</h2>
                                <p className="text-muted mb-6 text-lg leading-relaxed">
                                    {t("bookList.whitePageText")}
                                </p>
                            </div>
                        </div>
                    )}
            </div>
            {
                bookGuide && <GuideTour stepId={0} steps={bookGuideSteps} onComplete={handleFirstBookGuide}
                                        onClose={() => setBookGuide(false)}/>
            }
        </div>
    );
}