import { WidgetConfigService, hookWidgetConfig } from '@c8y/ngx-components/context-dashboard';
import * as i0 from '@angular/core';
import { inject, Injector, Injectable } from '@angular/core';
import { PreviewService } from '@c8y/ngx-components';
import { gettext } from '@c8y/ngx-components/gettext';
import { AIService } from '@c8y/ngx-components/ai';
import { defaultWidgetIds } from '@c8y/ngx-components/widgets/definitions';
import { map, combineLatest, from, first } from 'rxjs';
import { HTML_AGENT } from '@c8y/ngx-components/ai/agents/html';

// Treat as "production" when run from Jest
const mode = (typeof __MODE__ !== 'undefined' ? __MODE__ : 'production');
const HTML_WIDGET_AGENT_DEFINITIONS = {
    snapshot: mode === 'development',
    label: gettext('HTML Widget Code assistant'),
    definition: HTML_AGENT
};

class AIHtmlWidgetConfigFactory {
    constructor() {
        this.betaPreviewService = inject(PreviewService);
        this.aiService = inject(AIService);
        /** The root injector (nb: components cannot be injected from here). */
        this.injector = inject(Injector);
        this.codeTag = 'c8y-code-extract';
        this.codeToolName = 'c8y-html-widget-code';
        this.queryToolName = 'cumulocity-api-request';
        this.widgetConfigService = inject(WidgetConfigService);
        this.aiWidgetConfigDefinition = {
            widgetId: defaultWidgetIds.HTML,
            label: gettext('AI Code Assistant'),
            loadComponent: () => import('@c8y/ngx-components/ai/agent-chat').then(m => m.WidgetAiChatSectionComponent),
            initialState: {
                // configuration to pass to WidgetAiChatSectionComponent
                agent: HTML_WIDGET_AGENT_DEFINITIONS,
                chatConfig: {
                    title: gettext('I’m your AI Code Assistant, here to help you build powerful widgets for your dashboard.'),
                    welcomeText: gettext('Describe the widget you want or select one of the options below to get started.')
                },
                loadComponentConfig: this.loadWidgetAiChatComponentConfig.bind(this),
                variables: this.widgetConfigService.currentConfig$.pipe(map((htmlWidgetConfig) => ({
                    currentHtmlWidgetCode: htmlWidgetConfig?.config?.code || '',
                    c8yContext: htmlWidgetConfig?.device || {}
                }))),
                suggestions: [
                    {
                        label: gettext('Measurement widget'),
                        prompt: gettext('Create a widget that shows the current measurement of this device.')
                    },
                    {
                        label: gettext('Device status widget'),
                        prompt: gettext('Create a widget that shows the status of my devices.')
                    },
                    {
                        label: gettext('Critical alarm widget'),
                        prompt: gettext('Create a widget that shows all critical alarms.')
                    }
                ]
            },
            priority: 100,
            injector: this.injector
        };
    }
    get() {
        return combineLatest([
            from(this.aiService.getAgentHealth()),
            this.betaPreviewService.getState$('ui.html-widget.v2').pipe(first())
        ]).pipe(map(([aiHealthCheck, state]) => {
            if (state && aiHealthCheck.isProviderConfigured) {
                return [this.aiWidgetConfigDefinition];
            }
            return [];
        }));
    }
    async loadWidgetAiChatComponentConfig(componentInjector) {
        const { HtmlWidgetConfigService, HtmlAiChatToolDetailsComponent } = await import('@c8y/ngx-components/widgets/implementations/html-widget');
        const htmlWidgetConfigService = componentInjector.get(HtmlWidgetConfigService);
        return {
            preprocessAgentMessage: (message, changed) => this.preprocessAgentMessage(message, changed, htmlWidgetConfigService),
            assistantMessageDisplayConfig: {
                toolDetailsComponent: toolCallPart => {
                    if (toolCallPart.toolName === this.codeToolName) {
                        return HtmlAiChatToolDetailsComponent;
                    }
                    return undefined;
                },
                toolCallConfig: {
                    [this.queryToolName]: {
                        executingLabel: gettext('Analyzing query…'),
                        completedLabel: gettext('Query analyzed')
                    },
                    [this.codeToolName]: {
                        executingLabel: gettext('Creating widget…'),
                        completedLabel: gettext('Widget created')
                    }
                },
                // To match current behaviour and to help with development, for now we show the JSON for all tool calls
                showDefaultToolDetails: 'all'
            }
        };
    }
    applyCurrentCode(code, htmlWidgetConfigService) {
        const newConfig = {
            code: code,
            css: '',
            devMode: true,
            legacy: false,
            options: { advancedSecurity: false, cssEncapsulation: false }
        };
        htmlWidgetConfigService.configChanged$.next(newConfig);
        htmlWidgetConfigService.widgetConfigService.updateConfig({ config: newConfig });
    }
    preprocessAgentMessage(message, changedPart, htmlWidgetConfigService) {
        // Rewrite HTML content generated by the agent in as text content as if it had come from a tool call
        if (!message.steps?.length)
            return message;
        const step = message.steps[message.steps.length - 1];
        const codeToolIndex = step.toolCalls?.findIndex(tc => tc.toolName === this.codeToolName);
        const codeTool = step.toolCalls?.[codeToolIndex];
        if (codeTool && codeTool.type !== 'tool-result') {
            // A code update tool call is in progress - accumulate text into input
            const input = `${codeTool.input?.code || ''}${step.text}`;
            codeTool.input.code = input;
            step.text = '';
            const closeIdx = input.indexOf(`</${this.codeTag}>`);
            if (closeIdx !== -1) {
                // Found closing tag - convert to result and start new step
                const beforeClose = input.substring(0, closeIdx);
                const afterClose = input.substring(closeIdx + `</${this.codeTag}>`.length);
                codeTool.input.code = beforeClose;
                codeTool.type = 'tool-result';
                // Move it from calls to results
                step.toolCalls = [];
                step.toolResults = [{ ...codeTool }];
                // Always create a new (fake) step after this (just like a real AI), to keep any future text and code update calls separate from this one
                message.steps.push({ type: 'text', text: afterClose });
                // Since this is a fake tool call not a real one, the tool result callback won't trigger so do this manually
                this.applyCurrentCode(codeTool.input.code, htmlWidgetConfigService);
            }
            else {
                // Replace with a new instance so that change detections works
                step.toolCalls[codeToolIndex] = { ...codeTool };
            }
        }
        else if (step.text) {
            // No in-progress code tag, so check for one
            const openIdx = step.text.indexOf(`<${this.codeTag}>`);
            if (openIdx !== -1) {
                const afterOpen = step.text.substring(openIdx + `<${this.codeTag}>`.length);
                step.text = step.text.substring(0, openIdx);
                // Start a new "step" to keep it separate and simple
                message.steps.push({
                    type: 'text',
                    text: '',
                    toolCalls: [
                        {
                            type: 'tool-input-streaming',
                            toolName: this.codeToolName,
                            toolCallId: this.codeToolName + message.steps.length, // add step number just to ensure uniqueness
                            input: { code: afterOpen }
                        }
                    ]
                });
            }
        }
        return message;
    }
    static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: AIHtmlWidgetConfigFactory, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
    static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: AIHtmlWidgetConfigFactory, providedIn: 'root' }); }
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: AIHtmlWidgetConfigFactory, decorators: [{
            type: Injectable,
            args: [{
                    providedIn: 'root'
                }]
        }] });

const htmlWidgetAIChatProviders = [hookWidgetConfig(AIHtmlWidgetConfigFactory)];

/**
 * Generated bundle index. Do not edit.
 */

export { htmlWidgetAIChatProviders };
//# sourceMappingURL=c8y-ngx-components-widgets-definitions-html-widget-ai-config.mjs.map
