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

/**
 * DataService - Smart routing layer between server API and local database
 * Automatically routes requests based on offline/online status
 */
export class DataService {
    private static isOffline: boolean = false;
    private static accessToken: string | null = null;

    /**
     * Set offline mode status
     */
    static setOfflineMode(offline: boolean): void {
        this.isOffline = offline;
    }

    /**
     * Set access token for API requests
     */
    static setAccessToken(token: string | null): void {
        this.accessToken = token;
    }

    /**
     * Check if currently offline
     */
    static isCurrentlyOffline(): boolean {
        return this.isOffline;
    }

    // ========== BOOK OPERATIONS ==========

    /**
     * Get all books
     */
    static async getBooks(): Promise<BookListProps[]> {
        if (this.isOffline) {
            // Use local database
            if (typeof window === 'undefined' || !(window as any).electron) {
                throw new Error('Electron API not available');
            }

            const result = await (window as any).electron.dbGetBooks();
            if (!result.success) {
                throw new Error(result.error || 'Failed to get books from local DB');
            }
            return result.data || [];
        } else {
            // Use server API
            if (!this.accessToken) {
                throw new Error('No access token available');
            }

            const response = await System.authGetQueryToServer<BookListProps[]>(
                'books',
                this.accessToken
            );

            return response.data || [];
        }
    }

    /**
     * Get a single book with all data
     */
    static async getBook(bookId: string): Promise<BookProps | null> {
        if (this.isOffline) {
            // Use local database
            if (typeof window === 'undefined' || !(window as any).electron) {
                throw new Error('Electron API not available');
            }

            const result = await (window as any).electron.dbGetBook(bookId);
            if (!result.success) {
                throw new Error(result.error || 'Failed to get book from local DB');
            }
            return result.data || null;
        } else {
            // Use server API
            if (!this.accessToken) {
                throw new Error('No access token available');
            }

            const response = await System.authGetQueryToServer<BookProps>(
                `books/${bookId}`,
                this.accessToken
            );

            return response.data || null;
        }
    }

    /**
     * Save or update a book
     */
    static async saveBook(book: BookProps | BookListProps, authorId?: string): Promise<void> {
        if (this.isOffline) {
            // Save to local database
            if (typeof window === 'undefined' || !(window as any).electron) {
                throw new Error('Electron API not available');
            }

            const result = await (window as any).electron.dbSaveBook(book, authorId);
            if (!result.success) {
                throw new Error(result.error || 'Failed to save book to local DB');
            }
        } else {
            // Save to server
            if (!this.accessToken) {
                throw new Error('No access token available');
            }

            const isUpdate = 'bookId' in book && book.bookId;
            if (isUpdate) {
                await System.authPutToServer(`books/${book.bookId || (book as any).id}`, book, this.accessToken);
            } else {
                await System.authPostToServer('books', book, this.accessToken);
            }

            // Also save to local DB for caching
            if (typeof window !== 'undefined' && (window as any).electron) {
                await (window as any).electron.dbSaveBook(book, authorId);
            }
        }
    }

    /**
     * Delete a book
     */
    static async deleteBook(bookId: string): Promise<void> {
        if (this.isOffline) {
            // Delete from local database
            if (typeof window === 'undefined' || !(window as any).electron) {
                throw new Error('Electron API not available');
            }

            const result = await (window as any).electron.dbDeleteBook(bookId);
            if (!result.success) {
                throw new Error(result.error || 'Failed to delete book from local DB');
            }
        } else {
            // Delete from server
            if (!this.accessToken) {
                throw new Error('No access token available');
            }

            await System.authDeleteToServer(`books/${bookId}`, {}, this.accessToken);

            // Also delete from local DB
            if (typeof window !== 'undefined' && (window as any).electron) {
                await (window as any).electron.dbDeleteBook(bookId);
            }
        }
    }

    // ========== CHAPTER OPERATIONS ==========

    /**
     * Save or update a chapter
     */
    static async saveChapter(chapter: ChapterProps, bookId: string, contentId?: string): Promise<void> {
        if (this.isOffline) {
            // Save to local database
            if (typeof window === 'undefined' || !(window as any).electron) {
                throw new Error('Electron API not available');
            }

            const result = await (window as any).electron.dbSaveChapter(chapter, bookId, contentId);
            if (!result.success) {
                throw new Error(result.error || 'Failed to save chapter to local DB');
            }
        } else {
            // Save to server
            if (!this.accessToken) {
                throw new Error('No access token available');
            }

            const isUpdate = !!chapter.chapterId;
            if (isUpdate) {
                await System.authPutToServer(`chapters/${chapter.chapterId}`, chapter, this.accessToken);
            } else {
                await System.authPostToServer('chapters', { ...chapter, bookId }, this.accessToken);
            }

            // Also save to local DB for caching
            if (typeof window !== 'undefined' && (window as any).electron) {
                await (window as any).electron.dbSaveChapter(chapter, bookId, contentId);
            }
        }
    }

    // ========== CHARACTER OPERATIONS ==========

    /**
     * Get all characters for a book
     */
    static async getCharacters(bookId: string): Promise<CharacterProps[]> {
        if (this.isOffline) {
            // Use local database
            if (typeof window === 'undefined' || !(window as any).electron) {
                throw new Error('Electron API not available');
            }

            const result = await (window as any).electron.dbGetCharacters(bookId);
            if (!result.success) {
                throw new Error(result.error || 'Failed to get characters from local DB');
            }
            return result.data || [];
        } else {
            // Use server API
            if (!this.accessToken) {
                throw new Error('No access token available');
            }

            const response = await System.authGetQueryToServer<CharacterProps[]>(
                `characters?bookId=${bookId}`,
                this.accessToken
            );

            return response.data || [];
        }
    }

    /**
     * Save or update a character
     */
    static async saveCharacter(character: CharacterProps, bookId: string): Promise<void> {
        if (this.isOffline) {
            // Save to local database
            if (typeof window === 'undefined' || !(window as any).electron) {
                throw new Error('Electron API not available');
            }

            const result = await (window as any).electron.dbSaveCharacter(character, bookId);
            if (!result.success) {
                throw new Error(result.error || 'Failed to save character to local DB');
            }
        } else {
            // Save to server
            if (!this.accessToken) {
                throw new Error('No access token available');
            }

            const isUpdate = !!character.id;
            if (isUpdate) {
                await System.authPutToServer(`characters/${character.id}`, character, this.accessToken);
            } else {
                await System.authPostToServer('characters', { ...character, bookId }, this.accessToken);
            }

            // Also save to local DB for caching
            if (typeof window !== 'undefined' && (window as any).electron) {
                await (window as any).electron.dbSaveCharacter(character, bookId);
            }
        }
    }

    // ========== AI CONVERSATION OPERATIONS ==========

    /**
     * Get all AI conversations for a book
     */
    static async getConversations(bookId: string): Promise<Conversation[]> {
        if (this.isOffline) {
            // Use local database
            if (typeof window === 'undefined' || !(window as any).electron) {
                throw new Error('Electron API not available');
            }

            const result = await (window as any).electron.dbGetConversations(bookId);
            if (!result.success) {
                throw new Error(result.error || 'Failed to get conversations from local DB');
            }
            return result.data || [];
        } else {
            // Use server API
            if (!this.accessToken) {
                throw new Error('No access token available');
            }

            const response = await System.authGetQueryToServer<Conversation[]>(
                `ai/conversations?bookId=${bookId}`,
                this.accessToken
            );

            return response.data || [];
        }
    }

    /**
     * Save an AI conversation (always saves locally when using AI)
     */
    static async saveConversation(conversation: Conversation, bookId: string): Promise<void> {
        // Always save AI conversations to local DB first
        if (typeof window !== 'undefined' && (window as any).electron) {
            const result = await (window as any).electron.dbSaveConversation(conversation, bookId);
            if (!result.success) {
                console.error('Failed to save conversation to local DB:', result.error);
            }
        }

        // If online, also sync to server
        if (!this.isOffline && this.accessToken) {
            try {
                const isUpdate = !!conversation.id;
                if (isUpdate) {
                    await System.authPutToServer(
                        `ai/conversations/${conversation.id}`,
                        conversation,
                        this.accessToken
                    );
                } else {
                    await System.authPostToServer(
                        'ai/conversations',
                        { ...conversation, bookId },
                        this.accessToken
                    );
                }
            } catch (error) {
                console.warn('Failed to sync conversation to server:', error);
                // Don't throw - local save succeeded
            }
        }
    }

    // ========== SYNC STATUS ==========

    /**
     * Get sync status from local database
     */
    static async getSyncStatus(): Promise<any[]> {
        if (typeof window === 'undefined' || !(window as any).electron) {
            return [];
        }

        const result = await (window as any).electron.dbGetSyncStatus();
        if (!result.success) {
            console.error('Failed to get sync status:', result.error);
            return [];
        }
        return result.data || [];
    }

    /**
     * Get pending changes awaiting sync
     */
    static async getPendingChanges(limit: number = 100): Promise<any[]> {
        if (typeof window === 'undefined' || !(window as any).electron) {
            return [];
        }

        const result = await (window as any).electron.dbGetPendingChanges(limit);
        if (!result.success) {
            console.error('Failed to get pending changes:', result.error);
            return [];
        }
        return result.data || [];
    }
}

export default DataService;
