import React, {useContext, useEffect, useRef, useState} from "react";
import {apiGet, apiPost} from "@/lib/api/client";
import {isDesktop} from '@/lib/configs';
import * as tauri from '@/lib/tauri';
import OfflineContext, {OfflineContextType} from '@/context/OfflineContext';
import {AlertContext, AlertContextProps} from "@/context/AlertContext";
import SearchBook from "./SearchBook";
import {useRouter} from "@/lib/navigation";
import {Book, ChevronLeft, ChevronRight, Download, Settings, Trash2} from 'lucide-react';
import Badge from "@/components/ui/Badge";
import {SessionContext, SessionContextProps} from "@/context/SessionContext";
import {BookProps} from "@/lib/types/book";
import {getBookTypeLabel} from "@/lib/utils/book";
import BookCard from "@/components/book/BookCard";
import BookCardSkeleton from "@/components/book/BookCardSkeleton";
import GuideTour, {GuideStep} from "@/components/GuideTour";
import {guideTourDone, setNewGuideTour} from "@/lib/utils/user";
import {useTranslations} from '@/lib/i18n';
import {LangContext, LangContextProps} from "@/context/LangContext";
import {BooksSyncContext, BooksSyncContextProps, SyncType} from "@/context/BooksSyncContext";
import {BookSyncCompare, SyncedBook} from "@/lib/types/synced-book";
import {SeriesListItemProps} from "@/lib/types/series";
import SeriesCard, {SeriesCardProps} from "@/components/series/SeriesCard";
import SeriesSetting from "@/components/series/SeriesSetting";

interface CategoryItem {
    type: 'book' | 'series';
    book?: BookProps;
    series?: SeriesCardProps;
}

export default function BookList() {
    const {session, setSession}: SessionContextProps = useContext<SessionContextProps>(SessionContext);
    const accessToken: string = session?.accessToken || '';
    const {errorMessage}: AlertContextProps = useContext<AlertContextProps>(AlertContext);
    const router = useRouter();
    const t = useTranslations();
    const {lang}: LangContextProps = useContext<LangContextProps>(LangContext)
    const {
        serverSyncedBooks, booksToSyncFromServer, booksToSyncToServer,
        serverOnlyBooks, localOnlyBooks
    }: BooksSyncContextProps = useContext<BooksSyncContextProps>(BooksSyncContext);
    const {isCurrentlyOffline, offlineMode}: OfflineContextType = useContext<OfflineContextType>(OfflineContext);

    const [searchQuery, setSearchQuery] = useState<string>('');
    const [groupedItems, setGroupedItems] = useState<Record<string, CategoryItem[]>>({});
    const [isLoadingBooks, setIsLoadingBooks] = useState<boolean>(true);
    const [showSeriesSettingId, setShowSeriesSettingId] = useState<string | null>(null);
    const carouselRefs = useRef<Record<string, HTMLDivElement | null>>({});

    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>
                        <Settings strokeWidth={1.75} className="mr-2 text-primary w-5 h-5 inline"/>
                        {t("bookList.guideStep2ContentGear")}
                    </p>
                    <p>
                        <Download strokeWidth={1.75} className="mr-2 text-primary w-5 h-5 inline"/>
                        {t("bookList.guideStep2ContentDownload")}
                    </p>
                    <p>
                        <Trash2 strokeWidth={1.75} className="mr-2 text-primary w-5 h-5 inline"/>
                        {t("bookList.guideStep2ContentTrash")}
                    </p>
                </div>
            ),
        },
    ]

    useEffect((): void => {
        if (groupedItems && Object.keys(groupedItems).length > 0) {
            const notDone: boolean = isCurrentlyOffline()
                ? localStorage.getItem('guide-tour-new-first-book') !== 'true'
                : guideTourDone(session.user?.guideTour || [], 'new-first-book');
            if (notDone) setBookGuide(true);
        }
    }, [groupedItems]);

    useEffect((): void => {
        const canLoad: boolean = !isDesktop ||
            (!isCurrentlyOffline() || offlineMode.isDatabaseInitialized);
        if (canLoad) loadBooksAndSeries().then();
    }, [serverSyncedBooks, offlineMode.isDatabaseInitialized, booksToSyncFromServer, booksToSyncToServer, serverOnlyBooks, localOnlyBooks]);

    useEffect((): void => {
        if (accessToken) loadBooksAndSeries().then();
    }, [accessToken]);

    async function handleFirstBookGuide(): Promise<void> {
        if (isCurrentlyOffline()) {
            localStorage.setItem('guide-tour-new-first-book', 'true');
            setBookGuide(false);
            return;
        }
        try {
            const response: boolean = await apiPost<boolean>(
                'logs/tour',
                {plateforme: 'desktop', tour: 'new-first-book'},
                session.accessToken, lang
            );
            if (response) {
                localStorage.setItem('guide-tour-new-first-book', 'true');
                setSession(setNewGuideTour(session, 'new-first-book'));
                setBookGuide(false);
            }
        } catch (error: unknown) {
            if (error instanceof Error) {
                errorMessage(error.message);
            } else {
                errorMessage(t("bookList.errorBookCreate"));
            }
        }
    }
    
    async function loadBooksAndSeries(): Promise<void> {
        setIsLoadingBooks(true);
        try {
            let booksResponse: BookProps[];
            let seriesResponse: SeriesListItemProps[];
            if (isDesktop && isCurrentlyOffline()) {
                booksResponse = await tauri.getBooks() as BookProps[];
                seriesResponse = await tauri.getSeriesList() as SeriesListItemProps[];
            } else {
                [booksResponse, seriesResponse] = await Promise.all([
                    apiGet<BookProps[]>('books', accessToken, lang),
                    apiGet<SeriesListItemProps[]>('series/list', accessToken, lang)
                ]);
            }
            
            if (booksResponse) {
                const seriesList: SeriesListItemProps[] = seriesResponse || [];
                
                // Créer un mapping bookId -> seriesInfo
                const bookToSeriesMap: Map<string, SeriesListItemProps> = new Map();
                seriesList.forEach((series: SeriesListItemProps): void => {
                    series.bookIds.forEach((bookId: string): void => {
                        bookToSeriesMap.set(bookId, series);
                    });
                });
                
                // Transformer les livres avec leur image
                const transformedBooks: BookProps[] = booksResponse.map((book: BookProps): BookProps => {
                    const imageDataUrl: string = book.coverImage ? 'data:image/jpeg;base64,' + book.coverImage : '';
                    return {
                        bookId: book.bookId,
                        type: getBookTypeLabel(book.type),
                        title: book.title,
                        subTitle: book.subTitle,
                        summary: book.summary,
                        serie: book.serie,
                        publicationDate: book.publicationDate,
                        desiredWordCount: book.desiredWordCount,
                        totalWordCount: 0,
                        coverImage: imageDataUrl,
                    };
                });
                
                // Grouper par catégorie avec séries
                const itemsByCategory: Record<string, CategoryItem[]> = {};
                const processedSeriesIds: Set<string> = new Set();
                
                transformedBooks.forEach((book: BookProps): void => {
                    const categoryLabel: string = t(book.type);
                    if (!itemsByCategory[categoryLabel]) {
                        itemsByCategory[categoryLabel] = [];
                    }
                    
                    const seriesInfo: SeriesListItemProps | undefined = bookToSeriesMap.get(book.bookId);
                    
                    if (seriesInfo && !processedSeriesIds.has(seriesInfo.id)) {
                        // Ce livre fait partie d'une série non encore traitée
                        processedSeriesIds.add(seriesInfo.id);
                        
                        // Récupérer tous les livres de cette série dans cette catégorie
                        const seriesBooks: BookProps[] = transformedBooks.filter(
                            (bookItem: BookProps): boolean => seriesInfo.bookIds.includes(bookItem.bookId)
                        );
                        
                        const seriesCard: SeriesCardProps = {
                            id: seriesInfo.id,
                            name: seriesInfo.name,
                            coverImage: seriesInfo.coverImage,
                            books: seriesBooks
                        };
                        
                        itemsByCategory[categoryLabel].push({
                            type: 'series',
                            series: seriesCard
                        });
                    } else if (!seriesInfo) {
                        // Livre individuel (pas dans une série)
                        itemsByCategory[categoryLabel].push({
                            type: 'book',
                            book: book
                        });
                    }
                    // Si le livre fait partie d'une série déjà traitée, on l'ignore car il est déjà dans le SeriesCard
                });
                
                // Ajouter les séries sans livres (orphelines)
                seriesList.forEach((series: SeriesListItemProps): void => {
                    if (series.bookIds.length === 0) {
                        const emptySeriesCategory: string = t('bookList.emptySeries');
                        if (!itemsByCategory[emptySeriesCategory]) {
                            itemsByCategory[emptySeriesCategory] = [];
                        }
                        
                        const emptySeriesCard: SeriesCardProps = {
                            id: series.id,
                            name: series.name,
                            coverImage: series.coverImage,
                            books: []
                        };
                        
                        itemsByCategory[emptySeriesCategory].push({
                            type: 'series',
                            series: emptySeriesCard
                        });
                    }
                });
                
                setGroupedItems(itemsByCategory);
            }
        } catch (error: unknown) {
            if (error instanceof Error) {
                errorMessage(error.message);
            } else {
                errorMessage(t("bookList.errorBooksFetch"));
            }
        } finally {
            setIsLoadingBooks(false);
        }
    }
    
    function getFilteredGroupedItems(): Record<string, CategoryItem[]> {
        if (!searchQuery) {
            return groupedItems;
        }
        
        const filtered: Record<string, CategoryItem[]> = {};
        
        Object.entries(groupedItems).forEach(([category, items]: [string, CategoryItem[]]): void => {
            const filteredItems: CategoryItem[] = items.filter((item: CategoryItem): boolean => {
                if (item.type === 'book' && item.book) {
                    return item.book.title.toLowerCase().includes(searchQuery.toLowerCase());
                }
                if (item.type === 'series' && item.series) {
                    // Recherche dans le nom de la série ou dans les titres des livres
                    const matchesSeriesName: boolean = item.series.name.toLowerCase().includes(searchQuery.toLowerCase());
                    const matchesBookTitle: boolean = item.series.books.some(
                        (book: BookProps): boolean => book.title.toLowerCase().includes(searchQuery.toLowerCase())
                    );
                    return matchesSeriesName || matchesBookTitle;
                }
                return false;
            });
            
            if (filteredItems.length > 0) {
                filtered[category] = filteredItems;
            }
        });
        
        return filtered;
    }
    
    function getTotalItemsCount(items: CategoryItem[]): number {
        return items.reduce((count: number, item: CategoryItem): number => {
            if (item.type === 'book') {
                return count + 1;
            }
            if (item.type === 'series' && item.series) {
                return count + item.series.books.length;
            }
            return count;
        }, 0);
    }
    
    function detectBookSyncStatus(bookId: string): SyncType {
        if (!isDesktop || isCurrentlyOffline()) return 'synced';
        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';
    }

    function handleBookClick(bookId: string): void {
        router.push(`/book/${bookId}`);
    }
    
    function handleSeriesSettingsClick(seriesId: string): void {
        setShowSeriesSettingId(seriesId);
    }
    
    function scrollCarousel(category: string, direction: 'left' | 'right'): void {
        const container: HTMLDivElement | null = carouselRefs.current[category];
        if (!container) return;
        const cardWidth: number = container.querySelector<HTMLDivElement>(':scope > div')?.offsetWidth || 250;
        const scrollAmount: number = cardWidth * 2;
        container.scrollBy({
            left: direction === 'left' ? -scrollAmount : scrollAmount,
            behavior: 'smooth'
        });
    }
    
    const filteredItems: Record<string, CategoryItem[]> = getFilteredGroupedItems();

    return (
        <div
            className="flex flex-col h-full overflow-hidden w-full text-text-primary font-['Lora']">
            <div className="flex flex-col w-full overflow-y-auto overflow-x-hidden h-full min-h-0 flex-grow">
                {session?.user && (
                    <div data-guide="search-bar" className="sticky top-0 z-10 w-full flex justify-center px-4 py-3">
                        <SearchBook searchQuery={searchQuery} setSearchQuery={setSearchQuery}/>
                    </div>
                )}
                {
                    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 rounded-xl w-32 animate-pulse"></div>
                                    <div className="h-6 bg-tertiary 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(filteredItems).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(filteredItems).map(([category, items]: [string, CategoryItem[]], index: number) => (
                                <div key={category} {...(index === 0 && {'data-guide': 'book-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>
                                            {category}
                                        </h2>
                                        <Badge variant="muted" size="md">
                                            {getTotalItemsCount(items)} {t("bookList.works")}
                                        </Badge>
                                    </div>
                                    
                                    <div className="group/carousel relative w-full">
                                        <div
                                            className="absolute left-3 top-1/2 -translate-y-1/2 z-10 opacity-0 group-hover/carousel:opacity-100">
                                            <button
                                                onClick={(): void => scrollCarousel(category, 'left')}
                                                className="flex items-center justify-center w-11 h-11 rounded-xl bg-primary-dark hover:bg-primary text-text-primary transition-all duration-200"
                                            >
                                                <ChevronLeft strokeWidth={1.75} className="w-5 h-5"/>
                                            </button>
                                        </div>
                                        
                                        <div
                                            ref={(el: HTMLDivElement | null) => {
                                                carouselRefs.current[category] = el;
                                            }}
                                            className="flex items-start w-full overflow-x-auto px-4 gap-2 scroll-smooth scrollbar-hide"
                                        >
                                            {items.map((item: CategoryItem, idx: number) => {
                                                if (item.type === 'book' && item.book) {
                                                    return (
                                                        <div key={item.book.bookId}
                                                             {...(idx === 0 && {'data-guide': 'book-card'})}
                                                             className={`flex-shrink-0 w-64 sm:w-52 md:w-48 lg:w-56 xl:w-64 p-2 box-border ${bookGuide && 'mb-[200px]'}`}>
                                                            <BookCard
                                                                book={item.book}
                                                                onClickCallback={handleBookClick}
                                                                index={idx}
                                                                syncStatus={detectBookSyncStatus(item.book.bookId)}
                                                            />
                                                        </div>
                                                    );
                                                }
                                                if (item.type === 'series' && item.series) {
                                                    return (
                                                        <SeriesCard
                                                            key={item.series.id}
                                                            series={item.series}
                                                            onBookClick={handleBookClick}
                                                            onSettingsClick={handleSeriesSettingsClick}
                                                        />
                                                    );
                                                }
                                                return null;
                                            })}
                                        </div>
                                        
                                        <div
                                            className="absolute right-3 top-1/2 -translate-y-1/2 z-10 opacity-0 group-hover/carousel:opacity-100">
                                            <button
                                                onClick={(): void => scrollCarousel(category, 'right')}
                                                className="flex items-center justify-center w-11 h-11 rounded-xl bg-primary-dark hover:bg-primary text-text-primary transition-all duration-200"
                                            >
                                                <ChevronRight strokeWidth={1.75} className="w-5 h-5"/>
                                            </button>
                                        </div>
                                    </div>
                                </div>
                            ))}
                        </>
                    ) : (
                        <div className="flex items-center justify-center h-full">
                            <div className="text-center p-8 max-w-lg">
                                <div className="mx-auto mb-6 w-fit">
                                    <div
                                        className="bg-primary/10 flex items-center justify-center w-16 h-16 rounded-2xl">
                                        <Book strokeWidth={1.75} className="text-primary w-8 h-8"/>
                                    </div>
                                </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)}/>
            }
            {showSeriesSettingId &&
                <SeriesSetting seriesId={showSeriesSettingId} onClose={() => setShowSeriesSettingId(null)}/>}
        </div>
    );
}
