'use client'
import {useCallback, useContext, useEffect, useState} from 'react';
import {SpellEditState, SpellListItem, SpellListResponse, SpellProps, SpellTagProps} from '@/lib/types/spell';
import {initialSpellState} from '@/lib/constants/spell';
import {SeriesSpellDetailResponse, SeriesSpellListItem, SeriesSpellListResponse} from '@/lib/types/series';
import {SessionContext, SessionContextProps} from '@/context/SessionContext';
import {BookContext, BookContextProps} from '@/context/BookContext';
import {AlertContext, AlertContextProps} from '@/context/AlertContext';
import {LangContext, LangContextProps} from '@/context/LangContext';
import {apiDelete, apiGet, apiPatch, apiPost, apiPut} from '@/lib/api/client';
import {useTranslations} from '@/lib/i18n';
import {ViewMode} from '@/lib/types/settings';
import {isDesktop} from '@/lib/configs';
import * as tauri from '@/lib/tauri';
import OfflineContext, {OfflineContextType} from '@/context/OfflineContext';

export interface UseSpellsConfig {
    entityType: 'book' | 'series';
    entityId: string;
}

export interface UseSpellsReturn {
    spells: SpellListItem[];
    seriesSpells: SeriesSpellListItem[];
    tags: SpellTagProps[];
    selectedSpell: SpellEditState | null;
    selectedSeriesSpell: SeriesSpellDetailResponse | null;
    toolEnabled: boolean;
    isLoading: boolean;
    isSeriesMode: boolean;
    bookSeriesId: string | null;
    showTagManager: boolean;
    viewMode: ViewMode;
    spellBackup: SpellEditState | null;
    selectSpell: (spell: SpellListItem) => Promise<void>;
    addNewSpell: () => void;
    clearSelection: () => void;
    saveSpell: () => Promise<boolean>;
    deleteSpell: (spellId: string) => Promise<void>;
    updateSpellField: (key: keyof SpellEditState, value: string | string[] | null) => void;
    toggleTool: (enabled: boolean) => Promise<void>;
    importFromSeries: (seriesSpellId: string) => Promise<void>;
    exportToSeries: () => Promise<void>;
    refreshSeriesSpells: () => Promise<void>;
    setSelectedSpell: React.Dispatch<React.SetStateAction<SpellEditState | null>>;
    setShowTagManager: (show: boolean) => void;
    
    enterDetailMode: (spell: SpellListItem) => Promise<void>;
    enterEditMode: () => void;
    exitEditMode: (save: boolean) => Promise<void>;
    backToList: () => void;
    
    createTag: (name: string, color: string) => Promise<SpellTagProps | null>;
    updateTag: (tagId: string, name: string, color: string) => Promise<boolean>;
    deleteTag: (tagId: string) => Promise<boolean>;
    handleSyncComplete: () => Promise<void>;
}

export function useSpells(config: UseSpellsConfig): UseSpellsReturn {
    const {entityType, entityId} = config;
    const t = useTranslations();
    const {lang}: LangContextProps = useContext<LangContextProps>(LangContext);
    const {session}: SessionContextProps = useContext<SessionContextProps>(SessionContext);
    const {book, setBook}: BookContextProps = useContext<BookContextProps>(BookContext);
    const {errorMessage, successMessage}: AlertContextProps = useContext<AlertContextProps>(AlertContext);
    const {isCurrentlyOffline}: OfflineContextType = useContext<OfflineContextType>(OfflineContext);

    const [spells, setSpells] = useState<SpellListItem[]>([]);
    const [seriesSpells, setSeriesSpells] = useState<SeriesSpellListItem[]>([]);
    const [tags, setTags] = useState<SpellTagProps[]>([]);
    const [selectedSpell, setSelectedSpell] = useState<SpellEditState | null>(null);
    const [selectedSeriesSpell, setSelectedSeriesSpell] = useState<SeriesSpellDetailResponse | null>(null);
    const [toolEnabled, setToolEnabled] = useState<boolean>(entityType === 'series' || (book?.tools?.spells ?? false));
    const [isLoading, setIsLoading] = useState<boolean>(true);
    const [showTagManager, setShowTagManager] = useState<boolean>(false);
    
    const [viewMode, setViewMode] = useState<ViewMode>('list');
    const [spellBackup, setSpellBackup] = useState<SpellEditState | null>(null);
    
    const isSeriesMode: boolean = entityType === 'series';
    const bookSeriesId: string | null = book?.seriesId || null;
    const userToken: string = session?.accessToken || '';
    
    useEffect(function (): void {
        if (entityId) {
            refreshSpells().then();
        }
    }, [entityId]);
    
    useEffect(function (): void {
        if (bookSeriesId && !isSeriesMode) {
            refreshSeriesSpells().then();
        }
    }, [bookSeriesId, isSeriesMode]);
    
    const refreshSeriesSpells = useCallback(async function (): Promise<void> {
        if (!bookSeriesId) return;
        try {
            const response: SeriesSpellListResponse = await apiGet<SeriesSpellListResponse>(
                'series/spell/list',
                userToken,
                lang,
                {seriesid: bookSeriesId}
            );
            if (response) {
                setSeriesSpells(response.spells);
            }
        } catch (e: unknown) {
            if (e instanceof Error) {
                errorMessage(e.message);
            }
        }
    }, [bookSeriesId, userToken, lang]);
    
    const refreshSpells = useCallback(async function (): Promise<void> {
        setIsLoading(true);
        try {
            if (isSeriesMode) {
                const response: SeriesSpellListResponse = await apiGet<SeriesSpellListResponse>(
                    'series/spell/list',
                    userToken,
                    lang,
                    {seriesid: entityId}
                );
                if (response) {
                    const mappedSpells: SpellListItem[] = response.spells.map(function (spell: SeriesSpellListItem): SpellListItem {
                        return {
                            id: spell.id,
                            name: spell.name,
                            description: spell.description,
                            tags: spell.tags ? spell.tags.map(function (tagId: string): SpellTagProps {
                                const foundTag: SpellTagProps | undefined = response.tags.find(function (t: SpellTagProps): boolean {
                                    return t.id === tagId;
                                });
                                return foundTag || {id: tagId, name: tagId, color: null};
                            }) : [],
                        };
                    });
                    setSpells(mappedSpells);
                    setTags(response.tags || []);
                }
            } else {
                let response: SpellListResponse;
                if (isDesktop && (isCurrentlyOffline() || book?.localBook)) {
                    response = await tauri.getSpellList(entityId, book?.tools?.spells ?? false) as SpellListResponse;
                } else {
                    response = await apiGet<SpellListResponse>('spell/list', userToken, lang, {
                        bookid: entityId
                    });
                }
                if (response) {
                    setSpells(response.spells.map(function (spell: SpellListItem): SpellListItem {
                        return {
                            ...spell,
                            tags: spell.tags || []
                        };
                    }));
                    setTags(response.tags || []);
                    setToolEnabled(response.enabled);
                    if (setBook && book) {
                        setBook({
                            ...book,
                            tools: {
                                characters: book.tools?.characters ?? false,
                                worlds: book.tools?.worlds ?? false,
                                locations: book.tools?.locations ?? false,
                                spells: response.enabled
                            }
                        });
                    }
                }
            }
        } catch (e: unknown) {
            if (e instanceof Error) {
                errorMessage(e.message);
            } else {
                errorMessage(t("common.unknownError"));
            }
        } finally {
            setIsLoading(false);
        }
    }, [entityId, isSeriesMode, userToken, lang, book, setBook, errorMessage, t]);
    
    const selectSpell = useCallback(async function (spell: SpellListItem): Promise<void> {
        const tagIds: string[] = spell.tags ? spell.tags.map(function (tag: SpellTagProps): string {
            return tag.id;
        }) : [];
        
        setSelectedSpell({
            id: spell.id,
            name: spell.name,
            description: spell.description,
            appearance: '',
            tags: tagIds,
            powerLevel: null,
            components: null,
            limitations: null,
            notes: null,
            seriesSpellId: spell.seriesSpellId || null,
        });
        setSelectedSeriesSpell(null);
        
        try {
            if (isSeriesMode) {
                const response: SeriesSpellDetailResponse = await apiGet<SeriesSpellDetailResponse>(
                    'series/spell/detail',
                    userToken,
                    lang,
                    {spellid: spell.id}
                );
                if (response) {
                    setSelectedSpell(function (prev: SpellEditState | null): SpellEditState | null {
                        if (!prev) return null;
                        return {
                            ...prev,
                            appearance: response.appearance,
                            powerLevel: response.powerLevel,
                            components: response.components,
                            limitations: response.limitations,
                            notes: response.notes,
                        };
                    });
                }
            } else {
                let response: SpellProps;
                if (isDesktop && (isCurrentlyOffline() || book?.localBook)) {
                    response = await tauri.getSpellDetail(spell.id) as SpellProps;
                } else {
                    response = await apiGet<SpellProps>('spell/detail', userToken, lang, {
                        spellid: spell.id
                    });
                }
                if (response) {
                    setSelectedSpell(function (prev: SpellEditState | null): SpellEditState | null {
                        if (!prev) return null;
                        return {
                            ...prev,
                            appearance: response.appearance,
                            powerLevel: response.powerLevel,
                            components: response.components,
                            limitations: response.limitations,
                            notes: response.notes,
                            seriesSpellId: response.seriesSpellId || null,
                        };
                    });
                    
                    if (response.seriesSpellId) {
                        const seriesSpellResponse: SeriesSpellDetailResponse = await apiGet<SeriesSpellDetailResponse>(
                            'series/spell/detail',
                            userToken,
                            lang,
                            {spellid: response.seriesSpellId}
                        );
                        if (seriesSpellResponse) {
                            setSelectedSeriesSpell(seriesSpellResponse);
                        }
                    }
                }
            }
        } catch (e: unknown) {
            if (e instanceof Error) {
                errorMessage(e.message);
            }
        }
    }, [isSeriesMode, userToken, lang, errorMessage]);
    
    const addNewSpell = useCallback(function (): void {
        setSelectedSpell({...initialSpellState});
        setSelectedSeriesSpell(null);
        setViewMode('edit');
        setSpellBackup(null);
    }, []);
    
    const clearSelection = useCallback(function (): void {
        setSelectedSpell(null);
        setSelectedSeriesSpell(null);
        setViewMode('list');
        setSpellBackup(null);
    }, []);
    
    const updateSpellField = useCallback(function (key: keyof SpellEditState, value: string | string[] | null): void {
        if (selectedSpell) {
            setSelectedSpell({...selectedSpell, [key]: value});
        }
    }, [selectedSpell]);
    
    const toggleTool = useCallback(async function (enabled: boolean): Promise<void> {
        if (isSeriesMode) return;
        try {
            let response: boolean;
            if (isDesktop && (isCurrentlyOffline() || book?.localBook)) {
                response = await tauri.updateBookToolSetting(book?.bookId ?? '', 'spells', enabled);
            } else {
                response = await apiPatch<boolean>('book/tool-setting', {
                    bookId: book?.bookId,
                    toolName: 'spells',
                    enabled: enabled
                }, userToken, lang);
            }
            if (response && setBook && book) {
                setToolEnabled(enabled);
                setBook({
                    ...book,
                    tools: {
                        characters: book.tools?.characters ?? false,
                        worlds: book.tools?.worlds ?? false,
                        locations: book.tools?.locations ?? false,
                        spells: enabled
                    }
                });
            }
        } catch (e: unknown) {
            if (e instanceof Error) {
                errorMessage(e.message);
            }
        }
    }, [isSeriesMode, book, setBook, userToken, lang, errorMessage]);
    
    const saveSpell = useCallback(async function (): Promise<boolean> {
        if (!selectedSpell) return false;
        
        if (selectedSpell.id === null) {
            return await addSpellInternal(selectedSpell);
        } else {
            return await updateSpellInternal(selectedSpell);
        }
    }, [selectedSpell]);
    
    async function addSpellInternal(spell: SpellEditState): Promise<boolean> {
        if (!spell.name) {
            errorMessage(t("spellComponent.errorNameRequired"));
            return false;
        }
        try {
            let newSpellId: string;
            const spellData: Record<string, string | string[] | null> = {
                ...(isSeriesMode ? {seriesId: entityId} : {bookId: entityId}),
                name: spell.name,
                description: spell.description,
                appearance: spell.appearance,
                tags: spell.tags,
                powerLevel: spell.powerLevel,
                components: spell.components,
                limitations: spell.limitations,
                notes: spell.notes,
            };
            if (isSeriesMode) {
                newSpellId = await apiPost<string>('series/spell/add', spellData, userToken, lang);
            } else if (isDesktop && (isCurrentlyOffline() || book?.localBook)) {
                newSpellId = await tauri.createSpell(entityId, spellData) as string;
            } else {
                newSpellId = await apiPost<string>('spell/add', spellData, userToken, lang);
            }
            if (!newSpellId) {
                errorMessage(t("spellComponent.errorAddSpell"));
                return false;
            }
            const resolvedTags: SpellTagProps[] = tags.filter(function (tag: SpellTagProps): boolean {
                return spell.tags.includes(tag.id);
            });
            const newSpellListItem: SpellListItem = {
                id: newSpellId,
                name: spell.name,
                description: spell.description.length > 150
                    ? spell.description.substring(0, 150) + '...'
                    : spell.description,
                tags: resolvedTags,
            };
            setSpells(function (prev: SpellListItem[]): SpellListItem[] {
                return [...prev, newSpellListItem];
            });
            setSelectedSpell(null);
            return true;
        } catch (e: unknown) {
            if (e instanceof Error) {
                errorMessage(e.message);
            } else {
                errorMessage(t("common.unknownError"));
            }
            return false;
        }
    }
    
    async function updateSpellInternal(spellToUpdate: SpellEditState): Promise<boolean> {
        if (!spellToUpdate.id) return false;
        if (!spellToUpdate.name) {
            errorMessage(t("spellComponent.errorNameRequired"));
            return false;
        }
        try {
            const spellData: Record<string, string | string[] | null> = {
                id: spellToUpdate.id,
                name: spellToUpdate.name,
                description: spellToUpdate.description,
                appearance: spellToUpdate.appearance,
                tags: spellToUpdate.tags,
                powerLevel: spellToUpdate.powerLevel,
                components: spellToUpdate.components,
                limitations: spellToUpdate.limitations,
                notes: spellToUpdate.notes,
            };
            let success: boolean;
            if (isSeriesMode) {
                success = await apiPut<boolean>('series/spell/update', spellData, userToken, lang);
            } else if (isDesktop && (isCurrentlyOffline() || book?.localBook)) {
                success = await tauri.updateSpell(spellToUpdate.id!, spellData);
            } else {
                success = await apiPut<boolean>('spell/update', spellData, userToken, lang);
            }
            if (!success) {
                errorMessage(t("spellComponent.errorUpdateSpell"));
                return false;
            }
            const resolvedTags: SpellTagProps[] = tags.filter(function (tag: SpellTagProps): boolean {
                return spellToUpdate.tags.includes(tag.id);
            });
            setSpells(function (prev: SpellListItem[]): SpellListItem[] {
                return prev.map(function (spell: SpellListItem): SpellListItem {
                    return spell.id === spellToUpdate.id ? {
                        id: spellToUpdate.id,
                        name: spellToUpdate.name,
                        description: spellToUpdate.description.length > 150
                            ? spellToUpdate.description.substring(0, 150) + '...'
                            : spellToUpdate.description,
                        tags: resolvedTags,
                    } : spell;
                });
            });
            setSelectedSpell(null);
            successMessage(t("spellComponent.successUpdate"));
            return true;
        } catch (e: unknown) {
            if (e instanceof Error) {
                errorMessage(e.message);
            } else {
                errorMessage(t("common.unknownError"));
            }
            return false;
        }
    }
    
    const deleteSpell = useCallback(async function (spellId: string): Promise<void> {
        try {
            let success: boolean;
            if (isSeriesMode) {
                success = await apiDelete<boolean>('series/spell/delete', {spellId}, userToken, lang);
            } else if (isDesktop && (isCurrentlyOffline() || book?.localBook)) {
                success = await tauri.deleteSpell(spellId, book?.bookId ?? '', Date.now());
            } else {
                success = await apiDelete<boolean>('spell/delete', {spellId}, userToken, lang);
            }
            if (!success) {
                errorMessage(t("spellComponent.errorDeleteSpell"));
                return;
            }
            setSpells(function (prev: SpellListItem[]): SpellListItem[] {
                return prev.filter(function (s: SpellListItem): boolean {
                    return s.id !== spellId;
                });
            });
            setSelectedSpell(null);
        } catch (e: unknown) {
            if (e instanceof Error) {
                errorMessage(e.message);
            } else {
                errorMessage(t("common.unknownError"));
            }
        }
    }, [isSeriesMode, userToken, lang, errorMessage, t]);
    
    const exportToSeries = useCallback(async function (): Promise<void> {
        if (!selectedSpell || !selectedSpell.id || !bookSeriesId) return;
        
        try {
            const seriesSpellId: string = await apiPost<string>(
                'series/spell/add',
                {
                    seriesId: bookSeriesId,
                    name: selectedSpell.name,
                    description: selectedSpell.description,
                    appearance: selectedSpell.appearance || '',
                    tags: [],
                    powerLevel: selectedSpell.powerLevel || null,
                    components: selectedSpell.components || null,
                    limitations: selectedSpell.limitations || null,
                    notes: selectedSpell.notes || null,
                },
                userToken,
                lang
            );
            
            if (seriesSpellId) {
                const updateSuccess: boolean = await apiPut<boolean>('spell/update', {
                    id: selectedSpell.id,
                    name: selectedSpell.name,
                    description: selectedSpell.description,
                    appearance: selectedSpell.appearance,
                    tags: selectedSpell.tags,
                    powerLevel: selectedSpell.powerLevel,
                    components: selectedSpell.components,
                    limitations: selectedSpell.limitations,
                    notes: selectedSpell.notes,
                    seriesSpellId: seriesSpellId
                }, userToken, lang);
                
                if (updateSuccess) {
                    setSelectedSpell({...selectedSpell, seriesSpellId: seriesSpellId});
                    setSpells(function (prev: SpellListItem[]): SpellListItem[] {
                        return prev.map(function (s: SpellListItem): SpellListItem {
                            return s.id === selectedSpell.id ? {...s, seriesSpellId: seriesSpellId} : s;
                        });
                    });
                    const newSeriesSpell: SeriesSpellListItem = {
                        id: seriesSpellId,
                        name: selectedSpell.name,
                        description: selectedSpell.description.length > 150
                            ? selectedSpell.description.substring(0, 150) + '...'
                            : selectedSpell.description,
                        tags: null,
                    };
                    setSeriesSpells(function (prev: SeriesSpellListItem[]): SeriesSpellListItem[] {
                        return [...prev, newSeriesSpell];
                    });
                    successMessage(t("spellComponent.exportSuccess"));
                }
            }
        } catch (e: unknown) {
            if (e instanceof Error) {
                errorMessage(e.message);
            }
        }
    }, [selectedSpell, bookSeriesId, userToken, lang, successMessage, errorMessage, t]);
    
    const importFromSeries = useCallback(async function (seriesSpellId: string): Promise<void> {
        try {
            const seriesSpellDetail: SeriesSpellDetailResponse = await apiGet<SeriesSpellDetailResponse>(
                'series/spell/detail',
                userToken,
                lang,
                {spellid: seriesSpellId}
            );
            
            if (!seriesSpellDetail) return;
            
            let createdSpellId: string;
            const spellImportData: Record<string, unknown> = {
                bookId: entityId,
                name: seriesSpellDetail.name,
                description: seriesSpellDetail.description,
                appearance: seriesSpellDetail.appearance || '',
                tags: [],
                powerLevel: seriesSpellDetail.powerLevel,
                components: seriesSpellDetail.components,
                limitations: seriesSpellDetail.limitations,
                notes: seriesSpellDetail.notes,
                seriesSpellId: seriesSpellId
            };
            if (isDesktop && (isCurrentlyOffline() || book?.localBook)) {
                createdSpellId = await tauri.createSpell(entityId, spellImportData) as string;
            } else {
                createdSpellId = await apiPost<string>('spell/add', spellImportData, userToken, lang);
            }
            
            if (createdSpellId) {
                const newSpellListItem: SpellListItem = {
                    id: createdSpellId,
                    name: seriesSpellDetail.name,
                    description: seriesSpellDetail.description.length > 150
                        ? seriesSpellDetail.description.substring(0, 150) + '...'
                        : seriesSpellDetail.description,
                    tags: [],
                    seriesSpellId: seriesSpellId,
                };
                setSpells(function (prev: SpellListItem[]): SpellListItem[] {
                    return [...prev, newSpellListItem];
                });
            }
        } catch (e: unknown) {
            if (e instanceof Error) {
                errorMessage(e.message);
            }
        }
    }, [entityId, userToken, lang, errorMessage, successMessage, t]);
    
    const createTag = useCallback(async function (name: string, color: string): Promise<SpellTagProps | null> {
        try {
            if (isSeriesMode) {
                const tagId: string = await apiPost<string>(
                    'series/spell/tag/add',
                    {
                        seriesId: entityId,
                        name: name,
                        color: color,
                    },
                    userToken,
                    lang
                );
                if (tagId) {
                    const newTag: SpellTagProps = {id: tagId, name: name, color: color};
                    setTags(function (prev: SpellTagProps[]): SpellTagProps[] {
                        return [...prev, newTag];
                    });
                    return newTag;
                }
                return null;
            } else if (isDesktop && (isCurrentlyOffline() || book?.localBook)) {
                const result = await tauri.createSpellTag(entityId, name, color);
                const newTag: SpellTagProps = result as SpellTagProps;
                if (newTag && newTag.id) {
                    setTags(function (prev: SpellTagProps[]): SpellTagProps[] {
                        return [...prev, newTag];
                    });
                    return newTag;
                }
                return null;
            } else {
                const newTag: SpellTagProps = await apiPost<SpellTagProps>('spell/tag/add', {
                    bookId: entityId,
                    name: name,
                    color: color,
                }, userToken, lang);
                if (newTag && newTag.id) {
                    setTags(function (prev: SpellTagProps[]): SpellTagProps[] {
                        return [...prev, newTag];
                    });
                    return newTag;
                }
                return null;
            }
        } catch (e: unknown) {
            if (e instanceof Error) {
                errorMessage(e.message);
            }
            return null;
        }
    }, [isSeriesMode, entityId, userToken, lang, errorMessage]);
    
    const updateTag = useCallback(async function (tagId: string, name: string, color: string): Promise<boolean> {
        try {
            let success: boolean;
            if (isSeriesMode) {
                success = await apiPut<boolean>('series/spell/tag/update', {
                    tagId, name, color
                }, userToken, lang);
            } else if (isDesktop && (isCurrentlyOffline() || book?.localBook)) {
                success = await tauri.updateSpellTag(tagId, name, color);
            } else {
                success = await apiPut<boolean>('spell/tag/update', {
                    tagId, name, color
                }, userToken, lang);
            }
            if (!success) {
                errorMessage(t("spellComponent.updateSuccess"));
                return false;
            }
            setTags(function (prev: SpellTagProps[]): SpellTagProps[] {
                return prev.map(function (tag: SpellTagProps): SpellTagProps {
                    return tag.id === tagId ? {id: tagId, name: name, color: color} : tag;
                });
            });
            return true;
        } catch (e: unknown) {
            if (e instanceof Error) {
                errorMessage(e.message);
            }
            return false;
        }
    }, [isSeriesMode, userToken, lang, errorMessage, t]);
    
    const deleteTag = useCallback(async function (tagId: string): Promise<boolean> {
        try {
            let success: boolean;
            if (isSeriesMode) {
                success = await apiDelete<boolean>('series/spell/tag/delete', {tagId}, userToken, lang);
            } else if (isDesktop && (isCurrentlyOffline() || book?.localBook)) {
                success = await tauri.deleteSpellTag(tagId, book?.bookId ?? '', Date.now());
            } else {
                success = await apiDelete<boolean>('spell/tag/delete', {
                    tagId, bookId: entityId
                }, userToken, lang);
            }
            if (success) {
                setTags(function (prev: SpellTagProps[]): SpellTagProps[] {
                    return prev.filter(function (tag: SpellTagProps): boolean {
                        return tag.id !== tagId;
                    });
                });
                return true;
            }
            return false;
        } catch (e: unknown) {
            if (e instanceof Error) {
                errorMessage(e.message);
            }
            return false;
        }
    }, [isSeriesMode, entityId, userToken, lang, errorMessage]);
    
    const handleSyncComplete = useCallback(async function (): Promise<void> {
        if (selectedSpell?.seriesSpellId) {
            const seriesSpellResponse: SeriesSpellDetailResponse = await apiGet<SeriesSpellDetailResponse>(
                'series/spell/detail',
                userToken,
                lang,
                {spellid: selectedSpell.seriesSpellId}
            );
            if (seriesSpellResponse) {
                setSelectedSeriesSpell(seriesSpellResponse);
            }
        }
    }, [selectedSpell?.seriesSpellId, userToken, lang]);
    
    const enterDetailMode = useCallback(async function (spell: SpellListItem): Promise<void> {
        await selectSpell(spell);
        setViewMode('detail');
        setSpellBackup(null);
    }, [selectSpell]);
    
    const enterEditMode = useCallback(function (): void {
        if (selectedSpell) {
            setSpellBackup({...selectedSpell});
        }
        setViewMode('edit');
    }, [selectedSpell]);
    
    const exitEditMode = useCallback(async function (save: boolean): Promise<void> {
        if (save) {
            const success: boolean = await saveSpell();
            if (!success) return;
            if (spellBackup) {
                setViewMode('detail');
            } else {
                setViewMode('list');
            }
        } else {
            if (spellBackup) {
                setSelectedSpell(spellBackup);
                setViewMode('detail');
            } else {
                setSelectedSpell(null);
                setViewMode('list');
            }
        }
        setSpellBackup(null);
    }, [saveSpell, spellBackup]);
    
    const backToList = useCallback(function (): void {
        setSelectedSpell(null);
        setSelectedSeriesSpell(null);
        setSpellBackup(null);
        setViewMode('list');
    }, []);
    
    return {
        spells,
        seriesSpells,
        tags,
        selectedSpell,
        selectedSeriesSpell,
        toolEnabled,
        isLoading,
        isSeriesMode,
        bookSeriesId,
        showTagManager,
        viewMode,
        spellBackup,
        selectSpell,
        addNewSpell,
        clearSelection,
        saveSpell,
        deleteSpell,
        updateSpellField,
        toggleTool,
        importFromSeries,
        exportToSeries,
        refreshSeriesSpells,
        setSelectedSpell,
        setShowTagManager,
        enterDetailMode,
        enterEditMode,
        exitEditMode,
        backToList,
        createTag,
        updateTag,
        deleteTag,
        handleSyncComplete,
    };
}
