'use client'
import {forwardRef, useContext, useEffect, useImperativeHandle, useState} from "react";
import System from "@/lib/models/System";
import {AlertContext} from "@/context/AlertContext";
import {SessionContext} from "@/context/SessionContext";
import {useTranslations} from "next-intl";
import {LangContext, LangContextProps} from "@/context/LangContext";
import {SeriesContext, SeriesContextProps} from "@/context/SeriesContext";
import {SeriesBookProps} from "@/lib/models/Series";
import {BooksSyncContext, BooksSyncContextProps} from "@/context/BooksSyncContext";
import {SyncedBook} from "@/lib/models/SyncedBook";
import {FontAwesomeIcon} from "@fortawesome/react-fontawesome";
import {faArrowDown, faArrowUp, faBook, faPlus, faSpinner, faTrash} from "@fortawesome/free-solid-svg-icons";
import OfflineContext, {OfflineContextType} from "@/context/OfflineContext";
import {LocalSyncQueueContext, LocalSyncQueueContextProps} from "@/context/SyncQueueContext";
import {SeriesSyncContext, SeriesSyncContextProps} from "@/context/SeriesSyncContext";
import {SyncedSeries, SyncedSeriesBook} from "@/lib/models/SyncedSeries";

function SeriesBooksManager(props: object, ref: React.Ref<{ handleSave: () => Promise<void> }>) {
    const t = useTranslations();
    const {lang} = useContext<LangContextProps>(LangContext);

    const {session} = useContext(SessionContext);
    const {seriesId, localSeries} = useContext<SeriesContextProps>(SeriesContext);
    const {serverSyncedBooks, setServerSyncedBooks, localSyncedBooks} = useContext<BooksSyncContextProps>(BooksSyncContext);
    const userToken: string = session?.accessToken ? session?.accessToken : '';
    const {errorMessage, successMessage} = useContext(AlertContext);
    const {isCurrentlyOffline} = useContext<OfflineContextType>(OfflineContext);
    const {addToQueue} = useContext<LocalSyncQueueContextProps>(LocalSyncQueueContext);
    const {localSyncedSeries, serverSyncedSeries} = useContext<SeriesSyncContextProps>(SeriesSyncContext);

    const [isLoading, setIsLoading] = useState<boolean>(true);
    const [seriesBooks, setSeriesBooks] = useState<SeriesBookProps[]>([]);
    const [selectedBookToAdd, setSelectedBookToAdd] = useState<string>('');
    const [availableBooks, setAvailableBooks] = useState<SyncedBook[]>([]);

    useEffect(function () {
        if (seriesId) {
            loadSeriesBooks();
        }
    }, [seriesId]);

    useEffect(function () {
        const booksInThisSeries: string[] = seriesBooks.map((book: SeriesBookProps) => book.bookId);
        let allBooks: SyncedBook[];
        let allSeries: SyncedSeries[];

        if (isCurrentlyOffline() || localSeries) {
            allBooks = localSyncedBooks;
            allSeries = localSyncedSeries;
        } else {
            allBooks = serverSyncedBooks;
            allSeries = serverSyncedSeries;
        }

        // Get all bookIds in OTHER series (not this one)
        const booksInOtherSeries: Set<string> = new Set(
            allSeries
                .filter((series: SyncedSeries): boolean => series.id !== seriesId)
                .flatMap((series: SyncedSeries): string[] =>
                    series.books.map((book: SyncedSeriesBook): string => book.bookId)
                )
        );

        // Filter out books already in this series AND books already in another series
        const filteredBooks: SyncedBook[] = allBooks.filter(
            (book: SyncedBook) => !booksInThisSeries.includes(book.id) && !booksInOtherSeries.has(book.id)
        );
        setAvailableBooks(filteredBooks);
    }, [seriesBooks, serverSyncedBooks, localSyncedBooks, serverSyncedSeries, localSyncedSeries, isCurrentlyOffline, localSeries, seriesId]);

    async function loadSeriesBooks(): Promise<void> {
        setIsLoading(true);
        try {
            let response: SeriesBookProps[];

            if (isCurrentlyOffline() || localSeries) {
                response = await window.electron.invoke<SeriesBookProps[]>('db:series:books', {seriesId});
            } else {
                response = await System.authGetQueryToServer<SeriesBookProps[]>(
                    'series/book/list',
                    userToken,
                    lang,
                    {seriesid: seriesId}
                );
            }

            if (response) {
                setSeriesBooks(response);
            }
        } catch (e: unknown) {
            if (e instanceof Error) {
                errorMessage(e.message);
            } else {
                errorMessage(t('seriesBooks.error.unknown'));
            }
        } finally {
            setIsLoading(false);
        }
    }

    useImperativeHandle(ref, function () {
        return {
            handleSave: handleSave
        };
    });

    async function handleSave(): Promise<void> {
        successMessage(t('seriesBooks.success.saved'));
    }

    async function handleAddBook(): Promise<void> {
        if (!selectedBookToAdd) {
            errorMessage(t('seriesBooks.error.selectBook'));
            return;
        }

        try {
            const addData = {
                seriesId: seriesId,
                bookId: selectedBookToAdd
            };
            let response: boolean;

            if (isCurrentlyOffline() || localSeries) {
                response = await window.electron.invoke<boolean>('db:series:book:add', addData);
            } else {
                response = await System.authPostToServer<boolean>(
                    'series/book/add',
                    addData,
                    userToken,
                    lang
                );

                if (localSyncedSeries.find((s: SyncedSeries): boolean => s.id === seriesId)) {
                    addToQueue('db:series:book:add', addData);
                }
            }

            if (response) {
                const allBooks: SyncedBook[] = isCurrentlyOffline() || localSeries ? localSyncedBooks : serverSyncedBooks;
                const addedBook: SyncedBook | undefined = allBooks.find(
                    (book: SyncedBook) => book.id === selectedBookToAdd
                );
                if (addedBook) {
                    const newSeriesBook: SeriesBookProps = {
                        bookId: addedBook.id,
                        title: addedBook.title,
                        order: seriesBooks.length + 1,
                        coverImage: null
                    };
                    setSeriesBooks([...seriesBooks, newSeriesBook]);

                    setServerSyncedBooks((prev: SyncedBook[]): SyncedBook[] =>
                        prev.map((book: SyncedBook): SyncedBook =>
                            book.id === selectedBookToAdd
                                ? {...book, seriesId: seriesId}
                                : book
                        )
                    );
                }
                setSelectedBookToAdd('');
            }
        } catch (e: unknown) {
            if (e instanceof Error) {
                errorMessage(e.message);
            } else {
                errorMessage(t('seriesBooks.error.unknown'));
            }
        }
    }

    async function handleRemoveBook(bookId: string): Promise<void> {
        try {
            const removeData = {
                seriesId: seriesId,
                bookId: bookId
            };
            let response: boolean;

            if (isCurrentlyOffline() || localSeries) {
                response = await window.electron.invoke<boolean>('db:series:book:remove', removeData);
            } else {
                response = await System.authDeleteToServer<boolean>(
                    'series/book/remove',
                    removeData,
                    userToken,
                    lang
                );

                if (localSyncedSeries.find((s: SyncedSeries): boolean => s.id === seriesId)) {
                    addToQueue('db:series:book:remove', removeData);
                }
            }

            if (response) {
                const updatedBooks: SeriesBookProps[] = seriesBooks
                    .filter((book: SeriesBookProps) => book.bookId !== bookId)
                    .map((book: SeriesBookProps, index: number) => ({
                        ...book,
                        order: index + 1
                    }));
                setSeriesBooks(updatedBooks);

                setServerSyncedBooks((prev: SyncedBook[]): SyncedBook[] =>
                    prev.map((book: SyncedBook): SyncedBook =>
                        book.id === bookId
                            ? {...book, seriesId: null}
                            : book
                    )
                );
            }
        } catch (e: unknown) {
            if (e instanceof Error) {
                errorMessage(e.message);
            } else {
                errorMessage(t('seriesBooks.error.unknown'));
            }
        }
    }

    async function handleMoveBook(bookId: string, direction: 'up' | 'down'): Promise<void> {
        const currentIndex: number = seriesBooks.findIndex((book: SeriesBookProps) => book.bookId === bookId);
        if (currentIndex === -1) return;

        const newIndex: number = direction === 'up' ? currentIndex - 1 : currentIndex + 1;
        if (newIndex < 0 || newIndex >= seriesBooks.length) return;

        const reorderedBooks: SeriesBookProps[] = [...seriesBooks];
        const [movedBook] = reorderedBooks.splice(currentIndex, 1);
        reorderedBooks.splice(newIndex, 0, movedBook);

        const updatedBooks: SeriesBookProps[] = reorderedBooks.map((book: SeriesBookProps, index: number) => ({
            ...book,
            order: index + 1
        }));

        try {
            const reorderData = {
                seriesId: seriesId,
                booksOrder: updatedBooks.map((book: SeriesBookProps) => ({
                    bookId: book.bookId,
                    order: book.order
                }))
            };
            let response: boolean;

            if (isCurrentlyOffline() || localSeries) {
                response = await window.electron.invoke<boolean>('db:series:book:reorder', reorderData);
            } else {
                response = await System.authPutToServer<boolean>(
                    'series/book/reorder',
                    reorderData,
                    userToken,
                    lang
                );

                if (localSyncedSeries.find((s: SyncedSeries): boolean => s.id === seriesId)) {
                    addToQueue('db:series:book:reorder', reorderData);
                }
            }

            if (response) {
                setSeriesBooks(updatedBooks);
            }
        } catch (e: unknown) {
            if (e instanceof Error) {
                errorMessage(e.message);
            } else {
                errorMessage(t('seriesBooks.error.unknown'));
            }
        }
    }

    if (isLoading) {
        return (
            <div className="flex items-center justify-center py-12">
                <FontAwesomeIcon icon={faSpinner} className="w-8 h-8 text-primary animate-spin"/>
            </div>
        );
    }

    return (
        <div className="space-y-6">
            <div className="bg-tertiary/90 backdrop-blur-sm rounded-xl p-5 border border-secondary/50 shadow-md">
                <h3 className="text-lg font-semibold text-text-primary mb-4">
                    {t('seriesBooks.addBook')}
                </h3>
                <div className="flex gap-3">
                    <select
                        value={selectedBookToAdd}
                        onChange={(e) => setSelectedBookToAdd(e.target.value)}
                        className="flex-1 bg-secondary/50 border border-secondary/50 rounded-lg px-4 py-2 text-text-primary focus:outline-none focus:border-primary"
                    >
                        <option value="">{t('seriesBooks.selectBookPlaceholder')}</option>
                        {availableBooks.map((book: SyncedBook) => (
                            <option key={book.id} value={book.id}>
                                {book.title}
                            </option>
                        ))}
                    </select>
                    <button
                        onClick={handleAddBook}
                        disabled={!selectedBookToAdd}
                        className="bg-primary hover:bg-primary-dark disabled:bg-secondary disabled:cursor-not-allowed text-white px-4 py-2 rounded-lg transition-colors duration-200 flex items-center gap-2"
                    >
                        <FontAwesomeIcon icon={faPlus} className="w-4 h-4"/>
                        {t('seriesBooks.add')}
                    </button>
                </div>
            </div>

            <div className="bg-tertiary/90 backdrop-blur-sm rounded-xl p-5 border border-secondary/50 shadow-md">
                <h3 className="text-lg font-semibold text-text-primary mb-4">
                    {t('seriesBooks.booksInSeries')} ({seriesBooks.length})
                </h3>

                {seriesBooks.length === 0 ? (
                    <div className="text-center py-8 text-text-secondary">
                        <FontAwesomeIcon icon={faBook} className="w-12 h-12 mb-4 opacity-50"/>
                        <p>{t('seriesBooks.noBooks')}</p>
                    </div>
                ) : (
                    <div className="space-y-2">
                        {seriesBooks
                            .sort((a: SeriesBookProps, b: SeriesBookProps) => a.order - b.order)
                            .map((book: SeriesBookProps, index: number) => (
                                <div
                                    key={book.bookId}
                                    className="flex items-center justify-between bg-secondary/30 rounded-lg p-3 border border-secondary/30 hover:border-primary/30 transition-colors duration-200"
                                >
                                    <div className="flex items-center gap-3">
                                        <span className="bg-primary/20 text-primary font-bold w-8 h-8 rounded-full flex items-center justify-center text-sm">
                                            {book.order}
                                        </span>
                                        <span className="text-text-primary font-medium">{book.title}</span>
                                    </div>
                                    <div className="flex items-center gap-2">
                                        <button
                                            onClick={() => handleMoveBook(book.bookId, 'up')}
                                            disabled={index === 0}
                                            className="p-2 rounded-lg hover:bg-secondary/50 disabled:opacity-30 disabled:cursor-not-allowed transition-colors duration-200"
                                            title={t('seriesBooks.moveUp')}
                                        >
                                            <FontAwesomeIcon icon={faArrowUp} className="w-4 h-4 text-text-secondary"/>
                                        </button>
                                        <button
                                            onClick={() => handleMoveBook(book.bookId, 'down')}
                                            disabled={index === seriesBooks.length - 1}
                                            className="p-2 rounded-lg hover:bg-secondary/50 disabled:opacity-30 disabled:cursor-not-allowed transition-colors duration-200"
                                            title={t('seriesBooks.moveDown')}
                                        >
                                            <FontAwesomeIcon icon={faArrowDown} className="w-4 h-4 text-text-secondary"/>
                                        </button>
                                        <button
                                            onClick={() => handleRemoveBook(book.bookId)}
                                            className="p-2 rounded-lg hover:bg-error/20 text-error transition-colors duration-200"
                                            title={t('seriesBooks.removeBook')}
                                        >
                                            <FontAwesomeIcon icon={faTrash} className="w-4 h-4"/>
                                        </button>
                                    </div>
                                </div>
                            ))}
                    </div>
                )}
            </div>
        </div>
    );
}

export default forwardRef(SeriesBooksManager);
