import * as i0 from '@angular/core';
import { Injectable, inject, ViewChild, Input, ChangeDetectionStrategy, Component } from '@angular/core';
import { WidgetConfigService } from '@c8y/ngx-components/context-dashboard';
import { of, BehaviorSubject, switchMap, tap, map as map$1, combineLatest, Subject } from 'rxjs';
import * as i2 from '@angular/forms';
import { FormBuilder, FormsModule, ReactiveFormsModule } from '@angular/forms';
import { DatapointSelectorModule } from '@c8y/ngx-components/datapoint-selector';
import * as i1 from '@c8y/ngx-components';
import { DynamicComponentAlertAggregator, DynamicComponentAlert, MeasurementRealtimeService, CommonModule, CoreModule } from '@c8y/ngx-components';
import * as i1$1 from 'ngx-echarts';
import { NgxEchartsModule, NGX_ECHARTS_CONFIG } from 'ngx-echarts';
import { AsyncPipe } from '@angular/common';
import { map, catchError } from 'rxjs/operators';
import { ChartAlertsComponent } from '@c8y/ngx-components/echart';
import { TranslateService } from '@ngx-translate/core';
import { gettext } from '@c8y/ngx-components/gettext';
import * as echarts from 'echarts';

class CurrentMeasurementService {
    constructor(realtime) {
        this.realtime = realtime;
    }
    /**
     * Fetches the latest measurement value for a given datapoint.
     * Combines initial historical value with realtime updates.
     *
     * @param datapoint - The KPI datapoint configuration
     * @returns Observable emitting measurement value, unit, date, and notFound flag
     */
    getLatest(datapoint) {
        return this.realtime
            .latestValueOfSpecificMeasurement$(datapoint.fragment, datapoint.series, datapoint.__target, 1, true)
            .pipe(map(m => {
            if (!m) {
                return {
                    value: Number.NaN,
                    unit: datapoint.unit || '',
                    date: '',
                    notFound: true
                };
            }
            const v = m[datapoint.fragment][datapoint.series];
            return {
                value: v.value,
                unit: v.unit || datapoint.unit,
                date: m.time
            };
        }), catchError(() => of({
            value: Number.NaN,
            unit: datapoint.unit || '',
            date: '',
            notFound: true
        })));
    }
    static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.25", ngImport: i0, type: CurrentMeasurementService, deps: [{ token: i1.MeasurementRealtimeService }], target: i0.ɵɵFactoryTarget.Injectable }); }
    static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.3.25", ngImport: i0, type: CurrentMeasurementService, providedIn: 'root' }); }
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.25", ngImport: i0, type: CurrentMeasurementService, decorators: [{
            type: Injectable,
            args: [{ providedIn: 'root' }]
        }], ctorParameters: () => [{ type: i1.MeasurementRealtimeService }] });

/** Chart layout constants */
const CHART_LAYOUT = {
    PIE_CENTER: ['50%', '45%'],
    PIE_RADIUS: '80%',
    LEGEND_BOTTOM: '2%',
    EMPTY_STATE_FONT_SIZE: 30
};
class PieChartWidgetViewComponent {
    constructor() {
        this.activeDatapoints = [];
        this.alerts = new DynamicComponentAlertAggregator();
        this.configChanged$ = new BehaviorSubject(undefined);
        this.measurements = inject(CurrentMeasurementService);
        this.translateService = inject(TranslateService);
        this.chartOptions$ = this.configChanged$.pipe(switchMap(() => this.fetchMeasurements()), tap(entries => this.handleNegativeValues(entries)), map$1(entries => this.buildChartOptions(entries)), tap(options => this.updateChartInstance(options)));
    }
    ngOnChanges(_) {
        if (this.config?.datapoints?.length) {
            this.configChanged$.next();
        }
    }
    onChartInit(ec) {
        this.echartsInstance = ec;
    }
    /**
     * Fetches latest measurements for all configured datapoints.
     */
    fetchMeasurements() {
        this.activeDatapoints = this.config?.datapoints?.filter(dp => dp.__active);
        const streams = this.activeDatapoints.map(dp => this.measurements.getLatest(dp).pipe(map$1(m => this.mapToDatapointValue(dp, m))));
        return combineLatest(streams);
    }
    /**
     * Maps a datapoint and its measurement to a DatapointValue.
     */
    mapToDatapointValue(datapoint, measurement) {
        const rawValue = measurement.value;
        return {
            label: datapoint.label || '',
            value: rawValue < 0 || Number.isNaN(rawValue) ? 0 : rawValue,
            rawValue,
            unit: datapoint.unit || measurement.unit || '',
            color: datapoint.color || ''
        };
    }
    /**
     * Handles negative value alerts - clears existing alerts and adds warning if needed.
     */
    handleNegativeValues(entries) {
        this.alerts.clear();
        const negatives = entries.filter(e => e.rawValue < 0);
        if (negatives.length === 0) {
            return;
        }
        const negativeDpList = negatives
            .map(n => `${this.encodeHtml(n.label)}: ${n.rawValue} ${this.encodeHtml(n.unit)}`)
            .join('; ');
        const errorMessage = this.translateService.instant(gettext('Negative measurements received from data point(s): {{ datapoints }}'), { datapoints: negativeDpList });
        this.alerts.addAlerts(new DynamicComponentAlert({ type: 'warning', text: errorMessage }));
    }
    /**
     * Builds the ECharts options based on datapoint values.
     */
    buildChartOptions(datapoints) {
        if (this.isEmptyState(datapoints)) {
            return this.buildEmptyStateOptions();
        }
        return this.buildPieChartOptions(datapoints);
    }
    /**
     * Checks if chart should display empty state (no positive data).
     */
    isEmptyState(entries) {
        const hasPositiveData = entries.some(e => e.rawValue > 0);
        const hasNegativeData = entries.some(e => e.rawValue < 0);
        return !hasPositiveData && !hasNegativeData;
    }
    /**
     * Builds options for empty state display.
     */
    buildEmptyStateOptions() {
        return {
            title: {
                text: gettext('No data available.'),
                left: 'center',
                top: 'center',
                textStyle: { fontSize: CHART_LAYOUT.EMPTY_STATE_FONT_SIZE }
            },
            series: []
        };
    }
    /**
     * Builds the pie chart options with data.
     */
    buildPieChartOptions(entries) {
        const options = this.config.pieChartOptions;
        const total = this.calculateTotal(entries);
        return {
            tooltip: this.buildTooltipConfig(entries, options),
            legend: this.buildLegendConfig(options),
            series: [this.buildPieSeriesConfig(entries, total, options)]
        };
    }
    /**
     * Calculates total of all entry values.
     */
    calculateTotal(entries) {
        return entries.reduce((sum, e) => sum + e.value, 0);
    }
    /**
     * Builds tooltip configuration.
     */
    buildTooltipConfig(entries, options) {
        return {
            show: options?.showTooltips ?? false,
            formatter: (params) => {
                const entry = entries.find(e => e.label === params.name);
                const unit = entry?.unit || '';
                const value = params.value.toFixed(2);
                return `${this.encodeHtml(params.name)}: ${value} ${this.encodeHtml(unit)}`;
            }
        };
    }
    /**
     * Builds legend configuration.
     */
    buildLegendConfig(options) {
        return {
            bottom: CHART_LAYOUT.LEGEND_BOTTOM,
            left: 'center',
            show: options?.showLegend ?? false,
            formatter: (name) => {
                const match = name.match(/^(.+)_\d+$/);
                return match ? match[1] : name;
            }
        };
    }
    /**
     * Builds pie series configuration.
     */
    buildPieSeriesConfig(entries, total, options) {
        const showLegend = options?.showLegend ?? false;
        return {
            center: showLegend ? CHART_LAYOUT.PIE_CENTER : ['50%', '50%'],
            type: 'pie',
            radius: CHART_LAYOUT.PIE_RADIUS,
            label: {
                show: options?.showLabels ?? false,
                position: 'inside',
                formatter: (params) => this.formatPercentageLabel(params.value, total)
            },
            data: entries.map((e, index) => ({
                name: `${e.label}_${index}`,
                value: e.value,
                itemStyle: { color: e.color }
            }))
        };
    }
    /**
     * Formats percentage label for pie slice.
     */
    formatPercentageLabel(value, total) {
        const percentage = total > 0 ? Math.round((value / total) * 100) : 0;
        return percentage === 0 ? '' : `${percentage}%`;
    }
    /**
     * Updates the ECharts instance with new options.
     */
    updateChartInstance(options) {
        if (this.echartsInstance) {
            this.echartsInstance.setOption(options, true);
        }
    }
    /**
     * Encodes HTML to prevent XSS attacks.
     */
    encodeHtml(text) {
        return echarts.format.encodeHTML(text);
    }
    static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.25", ngImport: i0, type: PieChartWidgetViewComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
    static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "20.3.25", type: PieChartWidgetViewComponent, isStandalone: true, selector: "c8y-pie-chart", inputs: { config: "config" }, providers: [
            MeasurementRealtimeService,
            CurrentMeasurementService,
            { provide: NGX_ECHARTS_CONFIG, useFactory: () => ({ echarts: () => import('echarts') }) }
        ], viewQueries: [{ propertyName: "chart", first: true, predicate: ["chart"], descendants: true }], usesOnChanges: true, ngImport: i0, template: "<div class=\"p-relative fit-h overflow-hidden\">\n  <div\n    class=\"p-absolute fit-w fit-h\"\n    #chart\n    echarts\n    [options]=\"chartOptions$ | async\"\n    (chartInit)=\"onChartInit($event)\"\n  ></div>\n\n  <c8y-chart-alerts [alerts]=\"alerts\"></c8y-chart-alerts>\n</div>\n", dependencies: [{ kind: "ngmodule", type: NgxEchartsModule }, { kind: "directive", type: i1$1.NgxEchartsDirective, selector: "echarts, [echarts]", inputs: ["options", "theme", "initOpts", "merge", "autoResize", "loading", "loadingType", "loadingOpts"], outputs: ["chartInit", "optionsError", "chartClick", "chartDblClick", "chartMouseDown", "chartMouseMove", "chartMouseUp", "chartMouseOver", "chartMouseOut", "chartGlobalOut", "chartContextMenu", "chartHighlight", "chartDownplay", "chartSelectChanged", "chartLegendSelectChanged", "chartLegendSelected", "chartLegendUnselected", "chartLegendLegendSelectAll", "chartLegendLegendInverseSelect", "chartLegendScroll", "chartDataZoom", "chartDataRangeSelected", "chartGraphRoam", "chartGeoRoam", "chartTreeRoam", "chartTimelineChanged", "chartTimelinePlayChanged", "chartRestore", "chartDataViewChanged", "chartMagicTypeChanged", "chartGeoSelectChanged", "chartGeoSelected", "chartGeoUnselected", "chartAxisAreaSelected", "chartBrush", "chartBrushEnd", "chartBrushSelected", "chartGlobalCursorTaken", "chartRendered", "chartFinished"], exportAs: ["echarts"] }, { kind: "component", type: ChartAlertsComponent, selector: "c8y-chart-alerts", inputs: ["alerts"] }, { kind: "pipe", type: AsyncPipe, name: "async" }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.25", ngImport: i0, type: PieChartWidgetViewComponent, decorators: [{
            type: Component,
            args: [{ selector: 'c8y-pie-chart', providers: [
                        MeasurementRealtimeService,
                        CurrentMeasurementService,
                        { provide: NGX_ECHARTS_CONFIG, useFactory: () => ({ echarts: () => import('echarts') }) }
                    ], imports: [NgxEchartsModule, AsyncPipe, ChartAlertsComponent], changeDetection: ChangeDetectionStrategy.OnPush, template: "<div class=\"p-relative fit-h overflow-hidden\">\n  <div\n    class=\"p-absolute fit-w fit-h\"\n    #chart\n    echarts\n    [options]=\"chartOptions$ | async\"\n    (chartInit)=\"onChartInit($event)\"\n  ></div>\n\n  <c8y-chart-alerts [alerts]=\"alerts\"></c8y-chart-alerts>\n</div>\n" }]
        }], ctorParameters: () => [], propDecorators: { config: [{
                type: Input
            }], chart: [{
                type: ViewChild,
                args: ['chart', { static: false }]
            }] } });

class PieChartWidgetConfigComponent {
    constructor() {
        this.destroy$ = new Subject();
        this.widgetConfigService = inject(WidgetConfigService);
        this.formBuilder = inject(FormBuilder);
    }
    set previewMapSet(template) {
        if (template) {
            this.widgetConfigService.setPreview(template);
            return;
        }
        this.widgetConfigService.setPreview(null);
    }
    ngOnInit() {
        this.formGroup = this.initForm();
    }
    ngOnDestroy() {
        this.destroy$.next();
        this.destroy$.complete();
    }
    onBeforeSave(config) {
        if (!this.formGroup.valid || !config)
            return false;
        const formValue = this.formGroup.value;
        config.pieChartOptions = config.pieChartOptions || {
            showLabels: false,
            showLegend: false,
            showTooltips: false
        };
        config.pieChartOptions.showLabels = formValue.pieChartOptions.showLabels;
        config.pieChartOptions.showLegend = formValue.pieChartOptions.showLegend;
        config.pieChartOptions.showTooltips = formValue.pieChartOptions.showTooltips;
        this.widgetConfigService.updateConfig(config);
        return true;
    }
    initForm() {
        const form = this.formBuilder.group({
            pieChartOptions: this.formBuilder.group({
                showLabels: [this.config.pieChartOptions?.showLabels ?? false],
                showLegend: [this.config.pieChartOptions?.showLegend ?? false],
                showTooltips: [this.config.pieChartOptions?.showTooltips ?? false]
            })
        });
        return form;
    }
    static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.25", ngImport: i0, type: PieChartWidgetConfigComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
    static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.25", type: PieChartWidgetConfigComponent, isStandalone: true, selector: "app-pie-chart-config", inputs: { config: "config" }, viewQueries: [{ propertyName: "previewMapSet", first: true, predicate: ["pieChartPreview"], descendants: true }], ngImport: i0, template: "@if (formGroup) {\n  <div [formGroup]=\"formGroup\">\n    <fieldset class=\"c8y-fieldset\">\n      <legend>{{ 'Pie chart options' | translate }}</legend>\n      <div\n        class=\"d-flex flex-column gap-8 form-group-sm p-b-8\"\n        formGroupName=\"pieChartOptions\"\n      >\n        <label class=\"c8y-checkbox\">\n          <input\n            type=\"checkbox\"\n            formControlName=\"showLabels\"\n          />\n          <span></span>\n          <span>\n            {{ 'Show labels' | translate }}\n          </span>\n        </label>\n        <label class=\"c8y-checkbox\">\n          <input\n            type=\"checkbox\"\n            formControlName=\"showLegend\"\n          />\n          <span></span>\n          <span>\n            {{ 'Show legend' | translate }}\n          </span>\n        </label>\n        <label class=\"c8y-checkbox\">\n          <input\n            type=\"checkbox\"\n            formControlName=\"showTooltips\"\n          />\n          <span></span>\n          <span>\n            {{ 'Show tooltips' | translate }}\n          </span>\n        </label>\n      </div>\n    </fieldset>\n  </div>\n\n  <ng-template #pieChartPreview>\n    @if (config.datapoints?.length > 0) {\n      <c8y-pie-chart\n        class=\"w-100 h-100\"\n        [config]=\"{\n          datapoints: config.datapoints,\n          pieChartOptions: {\n            showLabels: formGroup.value.pieChartOptions.showLabels,\n            showLegend: formGroup.value.pieChartOptions.showLegend,\n            showTooltips: formGroup.value.pieChartOptions.showTooltips\n          }\n        }\"\n      ></c8y-pie-chart>\n    } @else {\n      <div class=\"col-md-6 d-col a-i-start j-c-center\">\n        <c8y-ui-empty-state\n          [icon]=\"'c8y-data-points'\"\n          [title]=\"'No data points selected' | translate\"\n          [subtitle]=\"'Select data point to render content' | translate\"\n          [horizontal]=\"false\"\n          data-cy=\"kpi-widget--empty-state-no-data-point-selected\"\n        >\n          <p c8y-guide-docs>\n            <small\n              translate\n              ngNonBindable\n            >\n              Find out more in the\n              <a c8y-guide-href=\"/docs/cockpit/widgets-collection/#kpi\">user documentation</a>.\n            </small>\n          </p>\n        </c8y-ui-empty-state>\n      </div>\n    }\n  </ng-template>\n}\n", dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "component", type: i1.EmptyStateComponent, selector: "c8y-ui-empty-state", inputs: ["icon", "title", "subtitle", "horizontal"] }, { kind: "directive", type: i1.C8yTranslateDirective, selector: "[translate],[ngx-translate]" }, { kind: "ngmodule", type: CoreModule }, { kind: "directive", type: i2.CheckboxControlValueAccessor, selector: "input[type=checkbox][formControlName],input[type=checkbox][formControl],input[type=checkbox][ngModel]" }, { kind: "directive", type: i2.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i2.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]" }, { kind: "directive", type: i1.RequiredInputPlaceholderDirective, selector: "input[required], input[formControlName]" }, { kind: "directive", type: i1.GuideHrefDirective, selector: "[c8y-guide-href]", inputs: ["c8y-guide-href"] }, { kind: "component", type: i1.GuideDocsComponent, selector: "[c8y-guide-docs]" }, { kind: "directive", type: i2.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { kind: "directive", type: i2.FormControlName, selector: "[formControlName]", inputs: ["formControlName", "disabled", "ngModel"], outputs: ["ngModelChange"] }, { kind: "directive", type: i2.FormGroupName, selector: "[formGroupName]", inputs: ["formGroupName"] }, { kind: "ngmodule", type: DatapointSelectorModule }, { kind: "ngmodule", type: FormsModule }, { kind: "ngmodule", type: ReactiveFormsModule }, { kind: "component", type: PieChartWidgetViewComponent, selector: "c8y-pie-chart", inputs: ["config"] }, { kind: "pipe", type: i1.C8yTranslatePipe, name: "translate" }] }); }
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.25", ngImport: i0, type: PieChartWidgetConfigComponent, decorators: [{
            type: Component,
            args: [{ selector: 'app-pie-chart-config', imports: [
                        CommonModule,
                        CoreModule,
                        DatapointSelectorModule,
                        FormsModule,
                        ReactiveFormsModule,
                        PieChartWidgetViewComponent
                    ], template: "@if (formGroup) {\n  <div [formGroup]=\"formGroup\">\n    <fieldset class=\"c8y-fieldset\">\n      <legend>{{ 'Pie chart options' | translate }}</legend>\n      <div\n        class=\"d-flex flex-column gap-8 form-group-sm p-b-8\"\n        formGroupName=\"pieChartOptions\"\n      >\n        <label class=\"c8y-checkbox\">\n          <input\n            type=\"checkbox\"\n            formControlName=\"showLabels\"\n          />\n          <span></span>\n          <span>\n            {{ 'Show labels' | translate }}\n          </span>\n        </label>\n        <label class=\"c8y-checkbox\">\n          <input\n            type=\"checkbox\"\n            formControlName=\"showLegend\"\n          />\n          <span></span>\n          <span>\n            {{ 'Show legend' | translate }}\n          </span>\n        </label>\n        <label class=\"c8y-checkbox\">\n          <input\n            type=\"checkbox\"\n            formControlName=\"showTooltips\"\n          />\n          <span></span>\n          <span>\n            {{ 'Show tooltips' | translate }}\n          </span>\n        </label>\n      </div>\n    </fieldset>\n  </div>\n\n  <ng-template #pieChartPreview>\n    @if (config.datapoints?.length > 0) {\n      <c8y-pie-chart\n        class=\"w-100 h-100\"\n        [config]=\"{\n          datapoints: config.datapoints,\n          pieChartOptions: {\n            showLabels: formGroup.value.pieChartOptions.showLabels,\n            showLegend: formGroup.value.pieChartOptions.showLegend,\n            showTooltips: formGroup.value.pieChartOptions.showTooltips\n          }\n        }\"\n      ></c8y-pie-chart>\n    } @else {\n      <div class=\"col-md-6 d-col a-i-start j-c-center\">\n        <c8y-ui-empty-state\n          [icon]=\"'c8y-data-points'\"\n          [title]=\"'No data points selected' | translate\"\n          [subtitle]=\"'Select data point to render content' | translate\"\n          [horizontal]=\"false\"\n          data-cy=\"kpi-widget--empty-state-no-data-point-selected\"\n        >\n          <p c8y-guide-docs>\n            <small\n              translate\n              ngNonBindable\n            >\n              Find out more in the\n              <a c8y-guide-href=\"/docs/cockpit/widgets-collection/#kpi\">user documentation</a>.\n            </small>\n          </p>\n        </c8y-ui-empty-state>\n      </div>\n    }\n  </ng-template>\n}\n" }]
        }], propDecorators: { config: [{
                type: Input
            }], previewMapSet: [{
                type: ViewChild,
                args: ['pieChartPreview']
            }] } });

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

export { PieChartWidgetConfigComponent, PieChartWidgetViewComponent };
//# sourceMappingURL=c8y-ngx-components-widgets-implementations-pie-chart.mjs.map
