'use client'
import {useCallback, useContext, useEffect, useState} from 'react';
import {
    initialSpellState,
    SpellEditState,
    SpellListItem,
    SpellListResponse,
    SpellProps,
    SpellTagProps
} from '@/lib/models/Spell';
import {SeriesSpellDetailResponse, SeriesSpellListItem, SeriesSpellListResponse} from '@/lib/models/Series';
import {SessionContext} from '@/context/SessionContext';
import {BookContext} from '@/context/BookContext';
import {AlertContext} from '@/context/AlertContext';
import {LangContext, LangContextProps} from '@/context/LangContext';
import System from '@/lib/models/System';
import {useTranslations} from 'next-intl';
import {ViewMode} from '@/shared/interface';
import OfflineContext, {OfflineContextType} from '@/context/OfflineContext';
import {LocalSyncQueueContext, LocalSyncQueueContextProps} from '@/context/SyncQueueContext';
import {BooksSyncContext, BooksSyncContextProps} from '@/context/BooksSyncContext';
import {SyncedBook} from '@/lib/models/SyncedBook';
import {SeriesContext, SeriesContextProps} from '@/context/SeriesContext';
import {SeriesSyncContext, SeriesSyncContextProps} from '@/context/SeriesSyncContext';
import {SyncedSeries} from '@/lib/models/SyncedSeries';

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} = useContext<LangContextProps>(LangContext);
    const {session} = useContext(SessionContext);
    const {book, setBook} = useContext(BookContext);
    const {errorMessage, successMessage} = useContext(AlertContext);
    const {isCurrentlyOffline} = useContext<OfflineContextType>(OfflineContext);
    const {addToQueue} = useContext<LocalSyncQueueContextProps>(LocalSyncQueueContext);
    const {localSyncedBooks} = useContext<BooksSyncContextProps>(BooksSyncContext);
    const {localSeries} = useContext<SeriesContextProps>(SeriesContext);
    const {localSyncedSeries} = useContext<SeriesSyncContextProps>(SeriesSyncContext);

    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 {
            let response: SeriesSpellListResponse;
            // Dual logic: offline ou livre local → IPC, sinon serveur
            if (isCurrentlyOffline() || book?.localBook) {
                response = await window.electron.invoke<SeriesSpellListResponse>(
                    'db:series:spell:list',
                    {seriesId: bookSeriesId}
                );
            } else {
                response = await System.authGetQueryToServer<SeriesSpellListResponse>(
                    'series/spell/list',
                    userToken,
                    lang,
                    {seriesid: bookSeriesId}
                );
            }
            if (response) {
                setSeriesSpells(response.spells);
            }
        } catch (e: unknown) {
            if (e instanceof Error) {
                console.error('Error loading series spells:', e.message);
            }
        }
    }, [bookSeriesId, userToken, lang, isCurrentlyOffline, book?.localBook]);

    const refreshSpells = useCallback(async function (): Promise<void> {
        setIsLoading(true);
        try {
            if (isSeriesMode) {
                // Series mode - dual logic
                let response: SeriesSpellListResponse;
                if (isCurrentlyOffline() || localSeries) {
                    response = await window.electron.invoke<SeriesSpellListResponse>(
                        'db:series:spell:list',
                        {seriesId: entityId}
                    );
                } else {
                    response = await System.authGetQueryToServer<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 (isCurrentlyOffline()) {
                    response = await window.electron.invoke<SpellListResponse>('db:spell:list', {bookid: entityId});
                } else if (book?.localBook) {
                    response = await window.electron.invoke<SpellListResponse>('db:spell:list', {bookid: entityId});
                } else {
                    response = await System.authGetQueryToServer<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, isCurrentlyOffline]);

    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) {
                // Series mode - dual logic
                let response: SeriesSpellDetailResponse;
                if (isCurrentlyOffline() || localSeries) {
                    response = await window.electron.invoke<SeriesSpellDetailResponse>(
                        'db:series:spell:detail',
                        {spellId: spell.id}
                    );
                } else {
                    response = await System.authGetQueryToServer<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 (isCurrentlyOffline()) {
                    response = await window.electron.invoke<SpellProps>('db:spell:detail', {spellid: spell.id});
                } else if (book?.localBook) {
                    response = await window.electron.invoke<SpellProps>('db:spell:detail', {spellid: spell.id});
                } else {
                    response = await System.authGetQueryToServer<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) {
                        let seriesSpellResponse: SeriesSpellDetailResponse;
                        if (isCurrentlyOffline() || book?.localBook) {
                            seriesSpellResponse = await window.electron.invoke<SeriesSpellDetailResponse>(
                                'db:series:spell:detail',
                                {spellId: response.seriesSpellId}
                            );
                        } else {
                            seriesSpellResponse = await System.authGetQueryToServer<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, isCurrentlyOffline, book?.localBook]);

    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 {
            const requestData = {
                bookId: book?.bookId,
                toolName: 'spells',
                enabled: enabled
            };
            let response: boolean;
            if (isCurrentlyOffline() || book?.localBook) {
                response = await window.electron.invoke<boolean>('db:book:tool:update', requestData);
            } else {
                response = await System.authPatchToServer<boolean>('book/tool-setting', requestData, userToken, lang);
                if (localSyncedBooks.find((sb: SyncedBook): boolean => sb.id === book?.bookId)) {
                    addToQueue('db:book:tool:update', requestData);
                }
            }
            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, isCurrentlyOffline, localSyncedBooks, addToQueue]);

    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;
            if (isSeriesMode) {
                // Series mode - dual logic
                const data = {
                    seriesId: 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 (isCurrentlyOffline() || localSeries) {
                    newSpellId = await window.electron.invoke<string>('db:series:spell:add', data);
                } else {
                    newSpellId = await System.authPostToServer<string>('series/spell/add', data, userToken, lang);
                    if (localSyncedSeries.find((s: SyncedSeries): boolean => s.id === entityId)) {
                        addToQueue('db:series:spell:add', {...data, id: newSpellId});
                    }
                }
            } else {
                const data = {
                    bookId: entityId,
                    spell: {
                        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 (isCurrentlyOffline() || book?.localBook) {
                    newSpellId = await window.electron.invoke<string>('db:spell:create', data);
                } else {
                    newSpellId = await System.authPostToServer<string>('spell/add', data, userToken, lang);
                    if (localSyncedBooks.find((sb: SyncedBook): boolean => sb.id === entityId)) {
                        addToQueue('db:spell:create', {...data, id: newSpellId});
                    }
                }
            }
            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 {
            let success: boolean;
            const data = {
                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,
            };
            if (isSeriesMode) {
                // Series mode - dual logic
                if (isCurrentlyOffline() || localSeries) {
                    success = await window.electron.invoke<boolean>('db:series:spell:update', data);
                } else {
                    success = await System.authPutToServer<boolean>('series/spell/update', data, userToken, lang);
                    if (localSyncedSeries.find((s: SyncedSeries): boolean => s.id === entityId)) {
                        addToQueue('db:series:spell:update', data);
                    }
                }
            } else {
                if (isCurrentlyOffline() || book?.localBook) {
                    success = await window.electron.invoke<boolean>('db:spell:update', data);
                } else {
                    success = await System.authPutToServer<boolean>('spell/update', data, userToken, lang);
                    if (localSyncedBooks.find((sb: SyncedBook): boolean => sb.id === entityId)) {
                        addToQueue('db:spell:update', data);
                    }
                }
            }
            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;
            const deletedAt: number = System.timeStampInSeconds();
            if (isSeriesMode) {
                // Series mode - dual logic
                const requestData = {spellId, deletedAt};
                if (isCurrentlyOffline() || localSeries) {
                    success = await window.electron.invoke<boolean>('db:series:spell:delete', requestData);
                } else {
                    success = await System.authDeleteToServer<boolean>('series/spell/delete', requestData, userToken, lang);
                    if (localSyncedSeries.find((s: SyncedSeries): boolean => s.id === entityId)) {
                        addToQueue('db:series:spell:delete', requestData);
                    }
                }
            } else {
                const requestData = {spellId, bookId: entityId, deletedAt};
                if (isCurrentlyOffline() || book?.localBook) {
                    success = await window.electron.invoke<boolean>('db:spell:delete', requestData);
                } else {
                    success = await System.authDeleteToServer<boolean>('spell/delete', requestData, userToken, lang);
                    if (localSyncedBooks.find((sb: SyncedBook): boolean => sb.id === entityId)) {
                        addToQueue('db:spell:delete', requestData);
                    }
                }
            }
            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, isCurrentlyOffline, book?.localBook, entityId, localSyncedBooks, addToQueue]);

    const exportToSeries = useCallback(async function (): Promise<void> {
        if (!selectedSpell || !selectedSpell.id || !bookSeriesId) return;

        try {
            const seriesSpellData = {
                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,
            };

            let seriesSpellId: string;
            if (isCurrentlyOffline() || book?.localBook) {
                // Mode offline ou livre local → IPC
                seriesSpellId = await window.electron.invoke<string>('db:series:spell:add', seriesSpellData);
            } else {
                // Mode online → Serveur
                seriesSpellId = await System.authPostToServer<string>(
                    'series/spell/add',
                    seriesSpellData,
                    userToken,
                    lang
                );
                // Si la série a une copie locale → addToQueue
                if (localSyncedSeries.find((s: SyncedSeries): boolean => s.id === bookSeriesId)) {
                    addToQueue('db:series:spell:add', {...seriesSpellData, id: seriesSpellId});
                }
            }

            if (seriesSpellId) {
                const updateData = {
                    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
                };

                let updateSuccess: boolean;
                if (isCurrentlyOffline() || book?.localBook) {
                    // Mode offline ou livre local → IPC
                    updateSuccess = await window.electron.invoke<boolean>('db:spell:update', updateData);
                } else {
                    // Mode online → Serveur
                    updateSuccess = await System.authPutToServer<boolean>('spell/update', updateData, userToken, lang);
                    // Si le livre a une copie locale → addToQueue
                    if (localSyncedBooks.find((sb: SyncedBook): boolean => sb.id === entityId)) {
                        addToQueue('db:spell:update', updateData);
                    }
                }

                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, isCurrentlyOffline, book, addToQueue, localSyncedBooks, localSyncedSeries, entityId]);

    const importFromSeries = useCallback(async function (seriesSpellId: string): Promise<void> {
        try {
            // 1. Récupérer les détails du sort de la série
            let seriesSpellDetail: SeriesSpellDetailResponse;
            if (isCurrentlyOffline() || book?.localBook) {
                // Mode offline → IPC pour récupérer les détails du sort de la série locale
                seriesSpellDetail = await window.electron.invoke<SeriesSpellDetailResponse>(
                    'db:series:spell:detail',
                    {spellId: seriesSpellId}
                );
            } else {
                // Mode online → Serveur
                seriesSpellDetail = await System.authGetQueryToServer<SeriesSpellDetailResponse>(
                    'series/spell/detail',
                    userToken,
                    lang,
                    {spellid: seriesSpellId}
                );
            }

            if (!seriesSpellDetail) return;

            // 2. Créer le sort dans le livre
            const spellData = {
                bookId: entityId,
                spell: {
                    name: seriesSpellDetail.name,
                    description: seriesSpellDetail.description,
                    appearance: seriesSpellDetail.appearance || '',
                    tags: [],
                    powerLevel: seriesSpellDetail.powerLevel,
                    components: seriesSpellDetail.components,
                    limitations: seriesSpellDetail.limitations,
                    notes: seriesSpellDetail.notes,
                    seriesSpellId: seriesSpellId
                }
            };

            let createdSpellId: string;
            if (isCurrentlyOffline() || book?.localBook) {
                // Mode offline ou livre local → IPC
                createdSpellId = await window.electron.invoke<string>('db:spell:create', spellData);
            } else {
                // Mode online → Serveur
                createdSpellId = await System.authPostToServer<string>('spell/add', spellData, userToken, lang);
                // Si le livre a une copie locale → addToQueue
                if (localSyncedBooks.find((sb: SyncedBook): boolean => sb.id === entityId)) {
                    addToQueue('db:spell:create', {...spellData, id: createdSpellId});
                }
            }

            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, isCurrentlyOffline, book, addToQueue, localSyncedBooks]);

    const createTag = useCallback(async function (name: string, color: string): Promise<SpellTagProps | null> {
        try {
            if (isSeriesMode) {
                // Series mode - dual logic
                const addData = {
                    seriesId: entityId,
                    name: name,
                    color: color,
                };
                let tagId: string;
                if (isCurrentlyOffline() || localSeries) {
                    tagId = await window.electron.invoke<string>('db:series:spell:tag:add', addData);
                } else {
                    tagId = await System.authPostToServer<string>(
                        'series/spell/tag/add',
                        addData,
                        userToken,
                        lang
                    );
                    if (localSyncedSeries.find((s: SyncedSeries): boolean => s.id === entityId)) {
                        addToQueue('db:series:spell:tag:add', {...addData, id: tagId});
                    }
                }
                if (tagId) {
                    const newTag: SpellTagProps = {id: tagId, name: name, color: color};
                    setTags(function (prev: SpellTagProps[]): SpellTagProps[] {
                        return [...prev, newTag];
                    });
                    return newTag;
                }
                return null;
            } else {
                const requestData = {
                    bookId: entityId,
                    name: name,
                    color: color,
                };
                let newTag: SpellTagProps;
                if (isCurrentlyOffline() || book?.localBook) {
                    newTag = await window.electron.invoke<SpellTagProps>('db:spell:tag:create', requestData);
                } else {
                    newTag = await System.authPostToServer<SpellTagProps>('spell/tag/add', requestData, userToken, lang);
                    if (localSyncedBooks.find((sb: SyncedBook): boolean => sb.id === entityId)) {
                        addToQueue('db:spell:tag:create', {...requestData, id: newTag?.id});
                    }
                }
                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, isCurrentlyOffline, book?.localBook, localSyncedBooks, addToQueue]);

    const updateTag = useCallback(async function (tagId: string, name: string, color: string): Promise<boolean> {
        try {
            let success: boolean;
            const requestData = {tagId, name, color};
            if (isSeriesMode) {
                // Series mode - dual logic
                if (isCurrentlyOffline() || localSeries) {
                    success = await window.electron.invoke<boolean>('db:series:spell:tag:update', requestData);
                } else {
                    success = await System.authPutToServer<boolean>('series/spell/tag/update', requestData, userToken, lang);
                    if (localSyncedSeries.find((s: SyncedSeries): boolean => s.id === entityId)) {
                        addToQueue('db:series:spell:tag:update', requestData);
                    }
                }
            } else {
                if (isCurrentlyOffline() || book?.localBook) {
                    success = await window.electron.invoke<boolean>('db:spell:tag:update', requestData);
                } else {
                    success = await System.authPutToServer<boolean>('spell/tag/update', requestData, userToken, lang);
                    if (localSyncedBooks.find((sb: SyncedBook): boolean => sb.id === entityId)) {
                        addToQueue('db:spell:tag:update', requestData);
                    }
                }
            }
            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, isCurrentlyOffline, book?.localBook, entityId, localSyncedBooks, addToQueue]);

    const deleteTag = useCallback(async function (tagId: string): Promise<boolean> {
        try {
            let success: boolean;
            const deletedAt: number = System.timeStampInSeconds();
            if (isSeriesMode) {
                // Series mode - dual logic
                const deleteData = {tagId, deletedAt};
                if (isCurrentlyOffline() || localSeries) {
                    success = await window.electron.invoke<boolean>('db:series:spell:tag:delete', deleteData);
                } else {
                    success = await System.authDeleteToServer<boolean>('series/spell/tag/delete', deleteData, userToken, lang);
                    if (localSyncedSeries.find((s: SyncedSeries): boolean => s.id === entityId)) {
                        addToQueue('db:series:spell:tag:delete', deleteData);
                    }
                }
            } else {
                const requestData = {tagId, bookId: entityId, deletedAt};
                if (isCurrentlyOffline() || book?.localBook) {
                    success = await window.electron.invoke<boolean>('db:spell:tag:delete', requestData);
                } else {
                    success = await System.authDeleteToServer<boolean>('spell/tag/delete', requestData, userToken, lang);
                    if (localSyncedBooks.find((sb: SyncedBook): boolean => sb.id === entityId)) {
                        addToQueue('db:spell:tag:delete', requestData);
                    }
                }
            }
            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, isCurrentlyOffline, book?.localBook, localSyncedBooks, addToQueue]);

    const handleSyncComplete = useCallback(async function (): Promise<void> {
        if (selectedSpell?.seriesSpellId) {
            let seriesSpellResponse: SeriesSpellDetailResponse;
            if (isCurrentlyOffline() || (isSeriesMode ? localSeries : book?.localBook)) {
                seriesSpellResponse = await window.electron.invoke<SeriesSpellDetailResponse>(
                    'db:series:spell:detail',
                    {spellId: selectedSpell.seriesSpellId}
                );
            } else {
                seriesSpellResponse = await System.authGetQueryToServer<SeriesSpellDetailResponse>(
                    'series/spell/detail',
                    userToken,
                    lang,
                    {spellid: selectedSpell.seriesSpellId}
                );
            }
            if (seriesSpellResponse) {
                setSelectedSeriesSpell(seriesSpellResponse);
            }
        }
    }, [selectedSpell?.seriesSpellId, userToken, lang, isCurrentlyOffline, isSeriesMode, localSeries, book?.localBook]);
    
    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,
    };
}
