import { BookProps, BookListProps } from '@/lib/models/Book';
import { CharacterProps } from '@/lib/models/Character';
import { Conversation } from '@/lib/models/QuillSense';
import { WorldProps } from '@/lib/models/World';
import { ChapterProps } from '@/lib/models/Chapter';

/**
 * OfflineDataService - Manages data retrieval with offline/online mode
 * Automatically caches to local DB when online, serves from local DB when offline
 */
export class OfflineDataService {
    private isOffline: boolean = false;

    /**
     * Set offline status (called by OfflineProvider)
     */
    setOfflineStatus(offline: boolean): void {
        this.isOffline = offline;
    }

    /**
     * Get current offline status
     */
    getOfflineStatus(): boolean {
        return this.isOffline;
    }

    /**
     * Get all books - from local DB if offline, from server otherwise
     */
    async getBooks(fetchFromServer: () => Promise<BookListProps[]>): Promise<BookListProps[]> {
        if (!window.electron) {
            return await fetchFromServer();
        }

        if (this.isOffline) {
            // Fetch from local DB
            const result = await window.electron.dbGetBooks();
            if (result.success && result.data) {
                const titles = result.data.map(b => b.title).join(', ');
                console.log(`📚 Books from LOCAL DB: ${titles}`);
                return result.data;
            }
            throw new Error(result.error || 'Failed to get books from local DB');
        } else {
            // Fetch from server and save to local DB
            const books = await fetchFromServer();
            const titles = books.map(b => b.title).join(', ');
            console.log(`📚 Books from SERVER: ${titles}`);

            // Save to local DB in background
            for (const book of books) {
                try {
                    await window.electron.dbSaveBook(book);
                } catch (error) {
                    console.error('Failed to save book to local DB:', error);
                }
            }

            return books;
        }
    }

    /**
     * Get single book - from local DB if offline, from server otherwise
     */
    async getBook(
        bookId: string,
        fetchFromServer: () => Promise<BookProps>
    ): Promise<BookProps> {
        if (!window.electron) {
            return await fetchFromServer();
        }

        if (this.isOffline) {
            const result = await window.electron.dbGetBook(bookId);
            if (result.success && result.data) {
                console.log(`📖 "${result.data.title}" from LOCAL DB`);
                return result.data;
            }
            throw new Error(result.error || 'Book not found in local DB');
        } else {
            const book = await fetchFromServer();
            console.log(`📖 "${book.title}" from SERVER`);

            // Save to local DB
            try {
                await window.electron.dbSaveBook(book);
            } catch (error) {
                console.error('Failed to save book to local DB:', error);
            }

            return book;
        }
    }

    /**
     * Create new book - creates on server if online, local UUID if offline
     */
    async createBook(
        bookData: Omit<BookProps, 'bookId'>,
        authorId: string,
        createOnServer: () => Promise<string>
    ): Promise<string> {
        if (!window.electron) {
            return await createOnServer();
        }

        if (this.isOffline) {
            // Generate local UUID and save to local DB
            const localBookId = crypto.randomUUID();
            const book: BookProps = { ...bookData, bookId: localBookId };
            await window.electron.dbSaveBook(book, authorId);
            console.log(`💾 Book "${book.title}" created locally (offline mode)`);
            return localBookId;
        } else {
            // Create on server and save to local DB
            const serverBookId = await createOnServer();
            const book: BookProps = { ...bookData, bookId: serverBookId };
            await window.electron.dbSaveBook(book, authorId);
            return serverBookId;
        }
    }

    /**
     * Save book - save to local DB and sync to server later if offline
     */
    async saveBook(
        book: BookProps,
        authorId: string | undefined,
        saveToServer: () => Promise<void>
    ): Promise<void> {
        if (!window.electron) {
            return await saveToServer();
        }

        // Always save to local DB first
        await window.electron.dbSaveBook(book, authorId);

        if (!this.isOffline) {
            // Also save to server
            try {
                await saveToServer();
            } catch (error) {
                console.error('Failed to save to server, will sync later:', error);
                // Data is already in local DB, will be synced later
            }
        } else {
            console.log(`💾 Book queued for sync (offline mode)`);
        }
    }

    /**
     * Get characters for a book
     */
    async getCharacters(
        bookId: string,
        fetchFromServer: () => Promise<CharacterProps[]>
    ): Promise<CharacterProps[]> {
        if (!window.electron) {
            return await fetchFromServer();
        }

        if (this.isOffline) {
            const result = await window.electron.dbGetCharacters(bookId);
            if (result.success && result.data) {
                const names = result.data.map(c => c.name).join(', ');
                console.log(`👤 Characters from LOCAL DB: ${names}`);
                return result.data;
            }
            throw new Error(result.error || 'Failed to get characters from local DB');
        } else {
            const characters = await fetchFromServer();
            const names = characters.map(c => c.name).join(', ');
            console.log(`👤 Characters from SERVER: ${names}`);

            // Save to local DB
            for (const character of characters) {
                try {
                    await window.electron.dbSaveCharacter(character, bookId);
                } catch (error) {
                    console.error('Failed to save character to local DB:', error);
                }
            }

            return characters;
        }
    }

    /**
     * Create character
     */
    async createCharacter(
        characterData: Omit<CharacterProps, 'id'>,
        bookId: string,
        createOnServer: () => Promise<string>
    ): Promise<string> {
        if (!window.electron) {
            return await createOnServer();
        }

        if (this.isOffline) {
            const localId = crypto.randomUUID();
            const character = { ...characterData, id: localId };
            await window.electron.dbSaveCharacter(character, bookId);
            console.log(`💾 Character "${character.name}" created locally (offline mode)`);
            return localId;
        } else {
            const serverId = await createOnServer();
            const character = { ...characterData, id: serverId };
            await window.electron.dbSaveCharacter(character, bookId);
            return serverId;
        }
    }

    /**
     * Save character
     */
    async saveCharacter(
        character: CharacterProps,
        bookId: string,
        saveToServer: () => Promise<void>
    ): Promise<void> {
        if (!window.electron) {
            return await saveToServer();
        }

        // Always save to local DB first
        await window.electron.dbSaveCharacter(character, bookId);

        if (!this.isOffline) {
            try {
                await saveToServer();
            } catch (error) {
                console.error('Failed to save to server, will sync later:', error);
            }
        } else {
            console.log(`💾 Character queued for sync (offline mode)`);
        }
    }

    /**
     * Get conversations for a book
     */
    async getConversations(
        bookId: string,
        fetchFromServer: () => Promise<Conversation[]>
    ): Promise<Conversation[]> {
        if (!window.electron) {
            return await fetchFromServer();
        }

        if (this.isOffline) {
            const result = await window.electron.dbGetConversations(bookId);
            if (result.success) {
                const titles = result.data?.map((c: any) => c.title).join(', ') || 'none';
                console.log(`💬 Conversations from LOCAL DB: ${titles}`);
                return result.data || [];
            }
            throw new Error(result.error || 'Failed to get conversations from local DB');
        } else {
            const conversations = await fetchFromServer();
            const titles = conversations.map(c => c.title).join(', ');
            console.log(`💬 Conversations from SERVER: ${titles}`);

            // Save to local DB
            for (const conversation of conversations) {
                try {
                    await window.electron.dbSaveConversation(conversation, bookId);
                } catch (error) {
                    console.error('Failed to save conversation to local DB:', error);
                }
            }

            return conversations;
        }
    }

    /**
     * Create conversation
     */
    async createConversation(
        conversationData: Omit<Conversation, 'id'>,
        bookId: string,
        createOnServer: () => Promise<string>
    ): Promise<string> {
        if (!window.electron) {
            return await createOnServer();
        }

        if (this.isOffline) {
            const localId = crypto.randomUUID();
            const conversation = { ...conversationData, id: localId };
            await window.electron.dbSaveConversation(conversation, bookId);
            console.log(`💾 Conversation "${conversation.title}" created locally (offline mode)`);
            return localId;
        } else {
            const serverId = await createOnServer();
            const conversation = { ...conversationData, id: serverId };
            await window.electron.dbSaveConversation(conversation, bookId);
            return serverId;
        }
    }

    /**
     * Save conversation
     */
    async saveConversation(
        conversation: Conversation,
        bookId: string,
        saveToServer: () => Promise<void>
    ): Promise<void> {
        if (!window.electron) {
            return await saveToServer();
        }

        // Always save to local DB first
        await window.electron.dbSaveConversation(conversation, bookId);

        if (!this.isOffline) {
            try {
                await saveToServer();
            } catch (error) {
                console.error('Failed to save to server, will sync later:', error);
            }
        } else {
            console.log(`💾 Conversation queued for sync (offline mode)`);
        }
    }

    /**
     * Create chapter
     */
    async createChapter(
        chapterData: Omit<ChapterProps, 'chapterId'>,
        bookId: string,
        createOnServer: () => Promise<string>
    ): Promise<string> {
        if (!window.electron) {
            return await createOnServer();
        }

        if (this.isOffline) {
            const localId = crypto.randomUUID();
            const chapter = { ...chapterData, chapterId: localId };
            await window.electron.dbSaveChapter(chapter, bookId);
            console.log(`💾 Chapter "${chapter.title}" created locally (offline mode)`);
            return localId;
        } else {
            const serverId = await createOnServer();
            const chapter = { ...chapterData, chapterId: serverId };
            await window.electron.dbSaveChapter(chapter, bookId);
            return serverId;
        }
    }

    /**
     * Save chapter content
     */
    async saveChapter(
        chapter: ChapterProps,
        bookId: string,
        saveToServer: () => Promise<void>
    ): Promise<void> {
        if (!window.electron) {
            return await saveToServer();
        }

        // Always save to local DB first
        await window.electron.dbSaveChapter(chapter, bookId);

        if (!this.isOffline) {
            try {
                await saveToServer();
            } catch (error) {
                console.error('Failed to save to server, will sync later:', error);
            }
        } else {
            console.log(`💾 Chapter "${chapter.title}" queued for sync (offline mode)`);
        }
    }
}

// Singleton instance
let offlineDataServiceInstance: OfflineDataService | null = null;

/**
 * Get OfflineDataService singleton instance
 */
export function getOfflineDataService(): OfflineDataService {
    if (!offlineDataServiceInstance) {
        offlineDataServiceInstance = new OfflineDataService();
    }
    return offlineDataServiceInstance;
}
