import { ServiceBubble } from '../../../types/service-bubble-class.js';
import { CredentialType } from '@bubblelab/shared-schemas';
import { MetabaseParamsSchema, MetabaseResultSchema, } from './metabase.schema.js';
import { parseMetabaseCredential, enhanceMetabaseErrorMessage, } from './metabase.utils.js';
/**
 * Metabase Service Bubble
 *
 * Integration with Metabase analytics and reporting platform.
 *
 * Features:
 * - Dashboard retrieval and listing
 * - Card (saved question) metadata
 * - Card query execution with parsed JSON results
 *
 * Supports self-hosted Metabase instances via configurable URL + API key.
 */
export class MetabaseBubble extends ServiceBubble {
    static type = 'service';
    static service = 'metabase';
    static authType = 'apikey';
    static bubbleName = 'metabase';
    static schema = MetabaseParamsSchema;
    static resultSchema = MetabaseResultSchema;
    static shortDescription = 'Metabase integration for dashboards, cards, and analytics queries';
    static longDescription = `
    Metabase service integration for business intelligence and analytics.

    Features:
    - Get dashboard metadata and dashcard list
    - List all available dashboards
    - Get card (saved question) metadata
    - Execute card queries and retrieve parsed JSON results

    Supports self-hosted Metabase instances with API key authentication.
  `;
    static alias = 'analytics';
    constructor(params = {
        operation: 'list_dashboards',
    }, context) {
        super(params, context);
    }
    async testCredential() {
        // Test by listing dashboards (minimal API call)
        const creds = this.getCredentials();
        if (!creds)
            return false;
        const response = await this.makeMetabaseRequest(creds, '/api/dashboard/', 'GET');
        if (!Array.isArray(response)) {
            throw new Error('Metabase API returned an invalid response');
        }
        return true;
    }
    chooseCredential() {
        const { credentials } = this.params;
        if (!credentials || typeof credentials !== 'object')
            return undefined;
        return credentials[CredentialType.METABASE_CRED];
    }
    getCredentials() {
        const rawCredential = this.chooseCredential();
        if (!rawCredential)
            return undefined;
        return parseMetabaseCredential(rawCredential);
    }
    async performAction(_context) {
        const { operation } = this.params;
        try {
            const result = await (async () => {
                const p = this.params;
                switch (p.operation) {
                    case 'get_dashboard':
                        return await this.getDashboard(p.dashboard_id);
                    case 'list_dashboards':
                        return await this.listDashboards();
                    case 'get_card':
                        return await this.getCard(p.card_id);
                    case 'query_card':
                        return await this.queryCard(p.card_id, p.parameters, p.pivot);
                    default:
                        throw new Error(`Unsupported operation: ${operation}`);
                }
            })();
            return result;
        }
        catch (error) {
            const errorMessage = error instanceof Error ? error.message : String(error);
            return {
                operation,
                success: false,
                error: errorMessage,
            };
        }
    }
    async getDashboard(dashboardId) {
        const creds = this.getCredentials();
        if (!creds) {
            return {
                operation: 'get_dashboard',
                success: false,
                error: 'Metabase credentials are required',
            };
        }
        const data = await this.makeMetabaseRequest(creds, `/api/dashboard/${dashboardId}`, 'GET');
        return {
            operation: 'get_dashboard',
            success: true,
            error: '',
            data: data,
        };
    }
    async listDashboards() {
        const creds = this.getCredentials();
        if (!creds) {
            return {
                operation: 'list_dashboards',
                success: false,
                error: 'Metabase credentials are required',
            };
        }
        const data = await this.makeMetabaseRequest(creds, '/api/dashboard/', 'GET');
        const dashboards = Array.isArray(data) ? data : [];
        return {
            operation: 'list_dashboards',
            success: true,
            error: '',
            data: {
                dashboards: dashboards,
                total: dashboards.length,
            },
        };
    }
    async getCard(cardId) {
        const creds = this.getCredentials();
        if (!creds) {
            return {
                operation: 'get_card',
                success: false,
                error: 'Metabase credentials are required',
            };
        }
        const data = await this.makeMetabaseRequest(creds, `/api/card/${cardId}`, 'GET');
        return {
            operation: 'get_card',
            success: true,
            error: '',
            data: data,
        };
    }
    async queryCard(cardId, parameters, pivot) {
        const creds = this.getCredentials();
        if (!creds) {
            return {
                operation: 'query_card',
                success: false,
                error: 'Metabase credentials are required',
            };
        }
        const body = parameters ? { parameters } : undefined;
        const endpoint = pivot
            ? `/api/card/pivot/${cardId}/query`
            : `/api/card/${cardId}/query`;
        const raw = (await this.makeMetabaseRequest(creds, endpoint, 'POST', body));
        // Flatten: extract rows/cols from Metabase's nested data.data structure
        const inner = raw.data ?? {};
        return {
            operation: 'query_card',
            success: true,
            error: '',
            data: {
                rows: inner.rows ?? [],
                cols: inner.cols ?? [],
                row_count: raw.row_count,
                status: raw.status,
            },
        };
    }
    async makeMetabaseRequest(creds, endpoint, method = 'GET', body) {
        const url = `${creds.url}${endpoint}`;
        const headers = {
            'x-api-key': creds.apiKey,
            'Content-Type': 'application/json',
        };
        const options = {
            method,
            headers,
        };
        if (body && method === 'POST') {
            options.body = JSON.stringify(body);
        }
        const response = await fetch(url, options);
        if (!response.ok) {
            let errorBody = '';
            try {
                const raw = await response.text();
                // Try JSON first — Metabase often returns { message: "..." }
                try {
                    const json = JSON.parse(raw);
                    errorBody = json.message || json.error || JSON.stringify(json);
                }
                catch {
                    // Strip HTML: remove script/style blocks entirely, then remaining tags
                    errorBody = raw.includes('<')
                        ? raw
                            .replace(/<script[\s\S]*?<\/script>/gi, '')
                            .replace(/<style[\s\S]*?<\/style>/gi, '')
                            .replace(/<[^>]*>/g, ' ')
                            .replace(/\s+/g, ' ')
                            .trim()
                        : raw;
                }
            }
            catch {
                // ignore parse error
            }
            const message = `Metabase API error (${response.status}): ${errorBody || response.statusText}`;
            throw new Error(enhanceMetabaseErrorMessage(message, response.status));
        }
        return await response.json();
    }
}
//# sourceMappingURL=metabase.js.map