'use client'
import {forwardRef, useContext, useEffect, useImperativeHandle, useState} from "react";
import OfflineContext, {OfflineContextType} from '@/context/OfflineContext';
import {isDesktop} from '@/lib/configs';
import {apiDelete, apiGet, apiPost, apiPut} from '@/lib/api/client';
import * as tauri from '@/lib/tauri';
import {AlertContext, AlertContextProps} from "@/context/AlertContext";
import {SessionContext, SessionContextProps} from "@/context/SessionContext";
import {useTranslations} from '@/lib/i18n';
import {LangContext, LangContextProps} from "@/context/LangContext";
import {SeriesContext, SeriesContextProps} from "@/context/SeriesContext";
import {SeriesBookProps} from "@/lib/types/series";
import {BooksSyncContext, BooksSyncContextProps} from "@/context/BooksSyncContext";
import {SyncedBook} from "@/lib/types/synced-book";
import {ArrowDown, ArrowUp, Book, Trash2} from 'lucide-react';
import PulseLoader from '@/components/ui/PulseLoader';
import InputField from '@/components/form/InputField';
import SelectBox from '@/components/form/SelectBox';
import IconButton from "@/components/ui/IconButton";
import EmptyState from "@/components/ui/EmptyState";
import Badge from "@/components/ui/Badge";
import EntityListItem from "@/components/ui/EntityListItem";

function SeriesBooksManager(props: object, ref: React.Ref<{ handleSave: () => Promise<void> }>) {
    const t = useTranslations();
    const {lang}: LangContextProps = useContext<LangContextProps>(LangContext);
    
    const {session}: SessionContextProps = useContext<SessionContextProps>(SessionContext);
    const {seriesId}: SeriesContextProps = useContext<SeriesContextProps>(SeriesContext);
    const {
        serverSyncedBooks,
        setServerSyncedBooks
    }: BooksSyncContextProps = useContext<BooksSyncContextProps>(BooksSyncContext);
    const userToken: string = session?.accessToken ? session?.accessToken : '';
    const {errorMessage, successMessage}: AlertContextProps = useContext<AlertContextProps>(AlertContext);
    const {isCurrentlyOffline} = useContext(OfflineContext);
    const useLocal: boolean = isDesktop && isCurrentlyOffline();
    
    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 booksInSeries: string[] = seriesBooks.map((book: SeriesBookProps) => book.bookId);
        const filteredBooks: SyncedBook[] = serverSyncedBooks.filter(
            (book: SyncedBook) => !booksInSeries.includes(book.id)
        );
        setAvailableBooks(filteredBooks);
    }, [seriesBooks, serverSyncedBooks]);
    
    async function loadSeriesBooks(): Promise<void> {
        setIsLoading(true);
        try {
            const response: SeriesBookProps[] = useLocal
                ? await tauri.getSeriesBooks(seriesId) as SeriesBookProps[]
                : await apiGet<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 response: boolean = useLocal
                ? await tauri.addBookToSeries(seriesId, selectedBookToAdd)
                : await apiPost<boolean>('series/book/add', {seriesId: seriesId, bookId: selectedBookToAdd}, userToken, lang);
            
            if (response) {
                const addedBook: SyncedBook | undefined = serverSyncedBooks.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 deletedAt: number = Math.floor(Date.now() / 1000);
            const response: boolean = useLocal
                ? await tauri.removeBookFromSeries(seriesId, bookId, deletedAt)
                : await apiDelete<boolean>('series/book/remove', {seriesId: seriesId, bookId: bookId}, userToken, lang);
            
            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 bookIds: string[] = updatedBooks.map((book: SeriesBookProps) => book.bookId);
            const response: boolean = useLocal
                ? await tauri.reorderSeriesBooks(seriesId, bookIds)
                : await apiPut<boolean>('series/book/reorder', {seriesId: seriesId, booksOrder: updatedBooks.map((book: SeriesBookProps) => ({bookId: book.bookId, order: book.order}))}, userToken, lang);
            
            if (response) {
                setSeriesBooks(updatedBooks);
            }
        } catch (e: unknown) {
            if (e instanceof Error) {
                errorMessage(e.message);
            } else {
                errorMessage(t('seriesBooks.error.unknown'));
            }
        }
    }
    
    if (isLoading) {
        return <PulseLoader/>;
    }

    return (
        <div className="space-y-6">
            <InputField
                fieldName={t('seriesBooks.addBook')}
                input={
                    <SelectBox
                        onChangeCallBack={(e) => setSelectedBookToAdd(e.target.value)}
                        data={availableBooks.map((book: SyncedBook) => ({label: book.title, value: book.id}))}
                        defaultValue={selectedBookToAdd}
                        placeholder={t('seriesBooks.selectBookPlaceholder')}
                    />
                }
                addButtonCallBack={handleAddBook}
                isAddButtonDisabled={!selectedBookToAdd}
            />
            
            <div>
                <p className="text-text-secondary text-sm font-medium mb-3">
                    {t('seriesBooks.booksInSeries')} ({seriesBooks.length})
                </p>

                {seriesBooks.length === 0 ? (
                    <EmptyState icon={Book} title={t('seriesBooks.noBooks')}/>
                ) : (
                    <div className="space-y-2">
                        {seriesBooks
                            .sort((a: SeriesBookProps, b: SeriesBookProps) => a.order - b.order)
                            .map((book: SeriesBookProps, index: number) => (
                                <EntityListItem
                                    key={book.bookId}
                                    onClick={function (): void {
                                    }}
                                    size="sm"
                                    avatar={<Badge variant="primary" size="sm">{book.order}</Badge>}
                                    title={book.title}
                                    extra={
                                        <div className="flex items-center gap-1">
                                            <IconButton
                                                icon={ArrowUp}
                                                variant="ghost"
                                                size="sm"
                                                onClick={() => handleMoveBook(book.bookId, 'up')}
                                                disabled={index === 0}
                                                tooltip={t('seriesBooks.moveUp')}
                                            />
                                            <IconButton
                                                icon={ArrowDown}
                                                variant="ghost"
                                                size="sm"
                                                onClick={() => handleMoveBook(book.bookId, 'down')}
                                                disabled={index === seriesBooks.length - 1}
                                                tooltip={t('seriesBooks.moveDown')}
                                            />
                                            <IconButton
                                                icon={Trash2}
                                                variant="danger"
                                                size="sm"
                                                onClick={() => handleRemoveBook(book.bookId)}
                                                tooltip={t('seriesBooks.removeBook')}
                                            />
                                        </div>
                                    }
                                />
                            ))}
                    </div>
                )}
            </div>
        </div>
    );
}

export default forwardRef(SeriesBooksManager);
