import { openDB } from 'idb';
import { parse as parseYaml } from 'yaml';
/**
 * HelpServiceController manages help topics stored in IndexedDB.
 * It supports loading topics from JSON or YAML files, querying, and searching.
 */
export class HelpServiceController {
    db = null;
    initPromise = null;
    /**
     * The current version of the help data.
     * Used to determine if an update is needed.
     */
    currentVersion;
    /**
     * The available help categories and their corresponding files.
     */
    categories;
    static DB_NAME = 'help-service';
    static DB_VERSION = 1;
    _initialized = false;
    /**
     * Indicates whether the help service has been initialized.
     * Initialization includes setting up the IndexedDB and loading help data if necessary.
     */
    get initialized() {
        return this._initialized;
    }
    /**
     * Promise that resolves when the help service is fully initialized.
     * If the service is already initialized, it resolves immediately.
     */
    get untilReady() {
        return this.initPromise ?? Promise.resolve();
    }
    constructor(init) {
        this.currentVersion = init.version;
        this.categories = Object.freeze(init.categories);
        this.initialize();
    }
    /**
     * Initialize the help service
     */
    async initialize() {
        if (this.initPromise) {
            return this.initPromise;
        }
        this.initPromise = this.doInitialize();
        return this.initPromise;
    }
    async doInitialize() {
        try {
            // Initialize IndexedDB
            await this.initDatabase();
            // Check if we need to update the help data
            await this.checkAndUpdateHelpData();
            this._initialized = true;
        }
        catch (error) {
            console.error('Failed to initialize help service:', error);
            throw error;
        }
    }
    /**
     * Initialize IndexedDB database
     */
    async initDatabase() {
        this.db = await openDB(HelpServiceController.DB_NAME, HelpServiceController.DB_VERSION, {
            upgrade(db) {
                // Create topics store
                if (!db.objectStoreNames.contains('topics')) {
                    const topicsStore = db.createObjectStore('topics', { keyPath: 'id' });
                    // Single field index for category queries
                    topicsStore.createIndex('category', 'category', { unique: false });
                    // Composite index for potential future complex queries
                    topicsStore.createIndex('category_id', ['category', 'id'], { unique: false });
                }
                // Create metadata store
                if (!db.objectStoreNames.contains('metadata')) {
                    db.createObjectStore('metadata', { keyPath: 'key' });
                }
            },
        });
    }
    /**
     * Check if help data needs to be updated and update if necessary
     */
    async checkAndUpdateHelpData() {
        if (!this.db || !this.currentVersion) {
            throw new Error('Database or version not initialized');
        }
        // Get stored version
        const storedMetadata = await this.db.get('metadata', 'version');
        const storedVersion = storedMetadata?.version;
        // If versions match, no update needed
        if (storedVersion === this.currentVersion) {
            return;
        }
        // Load and store help data from JSON files
        await this.loadHelpDataFromFiles();
        // Update stored version
        await this.db.put('metadata', {
            key: 'version',
            version: this.currentVersion,
            lastUpdated: Date.now(),
        });
    }
    /**
     * Load help data from JSON files and store in IndexedDB
     */
    async loadHelpDataFromFiles() {
        if (!this.db) {
            throw new Error('Database not initialized');
        }
        // Download all files first
        const allTopics = [];
        for (const filePath of Object.values(this.categories)) {
            const topics = await this.loadTopicsFromFile(filePath);
            // Prepare topics for insertion
            for (const topic of topics) {
                const topicKey = this.getTopicKey(topic.category, topic.id);
                allTopics.push({
                    ...topic,
                    id: topicKey,
                });
            }
        }
        // Insert all topics in a single transaction
        const topicsStore = this.db.transaction('topics', 'readwrite').objectStore('topics');
        // Clear existing topics
        await topicsStore.clear();
        // Insert all topics
        for (const topic of allTopics) {
            await topicsStore.put(topic);
        }
    }
    /**
     * Load topics from a JSON or YAML file
     */
    async loadTopicsFromFile(filePath) {
        const response = await fetch(filePath);
        if (!response.ok) {
            throw new Error(`Failed to fetch ${filePath}: ${response.status}`);
        }
        const text = await response.text();
        // Determine file type and parse accordingly
        if (filePath.endsWith('.yaml') || filePath.endsWith('.yml')) {
            return parseYaml(text);
        }
        else {
            return JSON.parse(text);
        }
    }
    /**
     * Generate a unique key for a topic
     */
    getTopicKey(category, id) {
        return `${category}::${id}`;
    }
    /**
     * Get a specific help topic
     */
    async getTopic(category, id) {
        await this.initialize();
        if (!this.db) {
            throw new Error('Database not initialized');
        }
        const topicKey = this.getTopicKey(category, id);
        const topic = await this.db.get('topics', topicKey);
        return topic || undefined;
    }
    /**
     * Get all topics for a specific category
     */
    async getTopicsByCategory(category) {
        await this.initialize();
        if (!this.db) {
            throw new Error('Database not initialized');
        }
        const topics = await this.db.getAllFromIndex('topics', 'category', category);
        return topics;
    }
    /**
     * Search topics by title or content
     */
    async searchTopics(query) {
        await this.initialize();
        if (!this.db) {
            throw new Error('Database not initialized');
        }
        const allTopics = await this.db.getAll('topics');
        const searchTerm = query.toLowerCase();
        return allTopics.filter((topic) => {
            const titleMatch = topic.title.toLowerCase().includes(searchTerm);
            const bodyMatch = topic.body.toLowerCase().includes(searchTerm);
            // Handle examples search for both string and array formats
            let examplesMatch = false;
            if (topic.examples) {
                if (typeof topic.examples === 'string') {
                    examplesMatch = topic.examples.toLowerCase().includes(searchTerm);
                }
                else if (Array.isArray(topic.examples)) {
                    examplesMatch = topic.examples.some((example) => example.value.toLowerCase().includes(searchTerm) ||
                        (example.title && example.title.toLowerCase().includes(searchTerm)));
                }
            }
            return titleMatch || bodyMatch || examplesMatch;
        });
    }
    /**
     * Get all available topics
     */
    async getAllTopics() {
        await this.initialize();
        if (!this.db) {
            throw new Error('Database not initialized');
        }
        return await this.db.getAll('topics');
    }
    /**
     * Get current version
     */
    getVersion() {
        return this.currentVersion;
    }
    /**
     * Force refresh of help data (useful for development)
     */
    async forceRefresh() {
        if (!this.db) {
            throw new Error('Database not initialized');
        }
        // Clear stored version to force update
        await this.db.delete('metadata', 'version');
        // Re-initialize
        this.initPromise = null;
        await this.initialize();
    }
    /**
     * Clear all help data from IndexedDB
     */
    async clearAllData() {
        if (!this.db) {
            throw new Error('Database not initialized');
        }
        const topicsStore = this.db.transaction('topics', 'readwrite').objectStore('topics');
        const metadataStore = this.db.transaction('metadata', 'readwrite').objectStore('metadata');
        await topicsStore.clear();
        await metadataStore.clear();
    }
}
//# sourceMappingURL=help_service_controller.js.map