import * as i3 from '@angular/common';
import { CommonModule } from '@angular/common';
import * as i0 from '@angular/core';
import { inject, input, output, signal, computed, effect, ChangeDetectionStrategy, ViewEncapsulation, Component } from '@angular/core';
import { AXPSpreadsheetComponent } from '@acorex/platform/layout/components';
import { AXPWidgetsList } from '@acorex/modules/common';
import { AXPEntityService, AXPEntityDataSelectorService, AXPEntityDefinitionRegistryService } from '@acorex/platform/layout/entity';
import { RootConfig } from './acorex-modules-learning-management.mjs';
import * as i1 from '@acorex/components/button';
import { AXButtonModule } from '@acorex/components/button';
import * as i2 from '@acorex/components/decorators';
import { AXDecoratorModule } from '@acorex/components/decorators';
import * as i4 from '@acorex/core/translation';
import { AXTranslationModule } from '@acorex/core/translation';

//#region ----   Imports   ----
//#endregion
class AXMLearningManagementSkillMatrixComponent {
    //#endregion
    //#region ----   Lifecycle Methods   ----
    constructor() {
        //#region ----   Services & Dependencies   ----
        this.entityService = inject(AXPEntityService);
        this.skillLevelDataAccessor = this.entityService
            .withEntity(RootConfig.module.name, RootConfig.entities.skillLevel.name)
            .data();
        this.skillDataAccessor = this.entityService
            .withEntity(RootConfig.module.name, RootConfig.entities.skill.name)
            .data();
        this.skillCategoryDataAccessor = this.entityService
            .withEntity(RootConfig.module.name, RootConfig.entities.skillCategory.name)
            .data();
        this.entityDataSelectorService = inject(AXPEntityDataSelectorService);
        this.entityResolver = inject(AXPEntityDefinitionRegistryService);
        //#endregion
        //#region ----   Inputs   ----
        /**
         * Array of job titles/positions to display as columns (e.g., Senior, Manager, Director)
         */
        this.titles = input([], ...(ngDevMode ? [{ debugName: "titles" }] : []));
        /**
         * Initial matrix data: { [skillId]: { [title.id]: skillLevelId } }
         */
        this.value = input({}, ...(ngDevMode ? [{ debugName: "value" }] : []));
        /**
         * Whether the matrix is in readonly mode
         */
        this.readonly = input(false, ...(ngDevMode ? [{ debugName: "readonly" }] : []));
        /**
         * Initial skill IDs (for syncing with parent entity)
         */
        this.skillIds = input([], ...(ngDevMode ? [{ debugName: "skillIds" }] : []));
        //#endregion
        //#region ----   Outputs   ----
        /**
         * Emitted when the matrix value changes
         */
        this.valueChange = output();
        /**
         * Emitted when a single cell value changes
         */
        this.cellChange = output();
        /**
         * Emitted when selected skills change (skill IDs array)
         */
        this.skillIdsChange = output();
        //#endregion
        //#region ----   Class Properties   ----
        /**
         * Skill levels loaded from the service
         */
        this.skillLevels = signal([], ...(ngDevMode ? [{ debugName: "skillLevels" }] : []));
        /**
         * Selected skills (internal state)
         */
        this.selectedSkills = signal([], ...(ngDevMode ? [{ debugName: "selectedSkills" }] : []));
        /**
         * Skill entity definition
         */
        this.skillEntityDef = signal(null, ...(ngDevMode ? [{ debugName: "skillEntityDef" }] : []));
        /**
         * Loading state
         */
        this.isLoading = signal(true, ...(ngDevMode ? [{ debugName: "isLoading" }] : []));
        /**
         * Loading state for skill entity
         */
        this.isLoadingSkillEntity = signal(false, ...(ngDevMode ? [{ debugName: "isLoadingSkillEntity" }] : []));
        //#endregion
        //#region ----   Computed Properties   ----
        /**
         * Vertical titles (skills) - rows of the matrix
         */
        this.verticalTitles = computed(() => {
            const skills = this.selectedSkills();
            const result = (skills ?? []).map((skill) => ({
                id: skill.id,
                title: skill.title,
                description: skill.description || undefined,
            }));
            return result;
        }, ...(ngDevMode ? [{ debugName: "verticalTitles" }] : []));
        /**
         * Horizontal titles (job titles/positions) - columns of the matrix
         */
        this.horizontalTitles = computed(() => {
            const titlesInput = this.titles();
            const result = (titlesInput ?? []).map((title) => ({
                id: title.id,
                title: title.title,
                description: title.description || undefined,
            }));
            return result;
        }, ...(ngDevMode ? [{ debugName: "horizontalTitles" }] : []));
        /**
         * Cell options (skill levels) - dropdown options for each cell, loaded from service
         */
        this.cellOptions = computed(() => {
            const levels = this.skillLevels();
            const result = (levels ?? []).map((level) => ({
                id: level.id,
                title: level.name,
                description: level.description || undefined,
            }));
            return result;
        }, ...(ngDevMode ? [{ debugName: "cellOptions" }] : []));
        /**
         * Spreadsheet columns - converted from horizontalTitles (job titles/positions)
         */
        this.spreadsheetColumns = computed(() => {
            const horizontalTitles = this.horizontalTitles();
            const cellOptions = this.cellOptions();
            // Create SelectBox widget configuration for skill levels
            const selectBoxWidget = {
                type: AXPWidgetsList.Editors.SelectBox,
                options: {
                    valueField: 'id',
                    textField: 'title',
                    dataSource: cellOptions.map(option => ({
                        id: option.id,
                        title: option.title,
                        description: option.description,
                    })),
                },
            };
            // Convert horizontal titles to columns
            return horizontalTitles.map((title) => ({
                name: title.id,
                title: title.title,
                description: title.description,
                path: title.id, // Path to access the value in row object
                widget: selectBoxWidget,
            }));
        }, ...(ngDevMode ? [{ debugName: "spreadsheetColumns" }] : []));
        /**
         * Spreadsheet rows - converted from matrix data and vertical titles
         */
        this.spreadsheetRows = computed(() => {
            const verticalTitles = this.verticalTitles();
            const horizontalTitles = this.horizontalTitles();
            const matrixData = this.value();
            // Convert matrix data to spreadsheet rows
            return verticalTitles.map((skill) => {
                const row = {
                    name: skill.id, // Required for fixed mode row identification
                    _skillTitle: skill.title, // For row header display
                    _skillDescription: skill.description, // For row header description
                };
                // Add cell values for each horizontal title (column)
                horizontalTitles.forEach((title) => {
                    const cellValue = matrixData[skill.id]?.[title.id] ?? null;
                    row[title.id] = cellValue;
                });
                return row;
            });
        }, ...(ngDevMode ? [{ debugName: "spreadsheetRows" }] : []));
        // Load skill levels and skill entity definition when component initializes
        this.loadSkillLevels();
        this.loadSkillEntityDef();
        // Watch for skillIds input changes and sync selected skills
        effect(() => {
            const ids = this.skillIds();
            if (ids && ids.length > 0 && this.skillEntityDef()) {
                this.loadSkillsByIds(ids);
            }
            else if (!ids || ids.length === 0) {
                // Try to extract skill IDs from matrix data keys
                const matrixData = this.value();
                const skillIdsFromMatrix = Object.keys(matrixData || {});
                if (skillIdsFromMatrix.length > 0 && this.skillEntityDef()) {
                    this.loadSkillsByIds(skillIdsFromMatrix);
                }
                else {
                    this.selectedSkills.set([]);
                }
            }
        });
        // Watch for matrix value changes and extract skill IDs
        effect(() => {
            const matrixData = this.value();
            const currentSkillIds = this.selectedSkills().map((s) => s.id);
            const skillIdsFromMatrix = Object.keys(matrixData || {});
            // If matrix has skills that aren't in selectedSkills, load them
            const missingIds = skillIdsFromMatrix.filter((id) => !currentSkillIds.includes(id));
            if (missingIds.length > 0 && this.skillEntityDef()) {
                this.loadSkillsByIds(missingIds);
            }
        });
    }
    //#endregion
    //#region ----   Data Loading Methods   ----
    /**
     * Load skill levels from the service
     */
    async loadSkillLevels() {
        try {
            this.isLoading.set(true);
            const query = {
                skip: 0,
                take: 1000,
                sort: [{ field: 'levelNumber', dir: 'asc' }],
            };
            const result = await this.skillLevelDataAccessor.query(query);
            this.skillLevels.set(result.items || []);
        }
        catch (error) {
            console.error('Error loading skill levels:', error);
            this.skillLevels.set([]);
        }
        finally {
            this.isLoading.set(false);
        }
    }
    /**
     * Load skill entity definition
     */
    async loadSkillEntityDef() {
        try {
            this.isLoadingSkillEntity.set(true);
            const entityDef = await this.entityResolver.resolve(RootConfig.module.name, RootConfig.entities.skill.name);
            this.skillEntityDef.set(entityDef);
        }
        catch (error) {
            console.error('Error loading skill entity definition:', error);
            this.skillEntityDef.set(null);
        }
        finally {
            this.isLoadingSkillEntity.set(false);
        }
    }
    /**
     * Load skills by IDs
     */
    async loadSkillsByIds(ids) {
        try {
            const skills = [];
            for (const id of ids) {
                try {
                    const skill = await this.skillDataAccessor.byKey(id);
                    if (skill) {
                        skills.push(skill);
                    }
                }
                catch (error) {
                    console.error(`Error loading skill ${id}:`, error);
                }
            }
            this.selectedSkills.set(skills);
        }
        catch (error) {
            console.error('Error loading skills by IDs:', error);
        }
    }
    //#endregion
    //#region ----   Data Transformation Methods   ----
    /**
     * Convert spreadsheet rows back to matrix data format
     */
    convertSpreadsheetRowsToMatrixData(rows) {
        const horizontalTitles = this.horizontalTitles();
        const matrixData = {};
        rows.forEach((row) => {
            const skillId = row['name']; // Row identifier (skill ID)
            if (!skillId) {
                return;
            }
            matrixData[skillId] = {};
            // Extract cell values for each column
            horizontalTitles.forEach((title) => {
                const cellValue = row[title.id] ?? null;
                matrixData[skillId][title.id] = cellValue;
            });
        });
        return matrixData;
    }
    //#endregion
    //#region ----   Event Handlers   ----
    /**
     * Handle spreadsheet change event - convert to matrix format
     */
    handleSpreadsheetChange(rows) {
        const matrixData = this.convertSpreadsheetRowsToMatrixData(rows);
        this.valueChange.emit(matrixData);
        // Extract skill IDs from row names and emit
        const skillIds = rows.map((row) => row['name']).filter((id) => id != null);
        this.skillIdsChange.emit(skillIds);
    }
    /**
     * Handle cell change event from spreadsheet
     */
    handleCellChange(event) {
        this.cellChange.emit(event);
    }
    /**
     * Open skill selector dialog with category filter
     */
    async handleSelectSkills() {
        const entityDef = this.skillEntityDef();
        if (!entityDef) {
            console.error('Skill entity definition not loaded');
            return;
        }
        try {
            // Get currently selected skill IDs
            const selectedItemIds = this.selectedSkills()
                .map((skill) => skill.id)
                .filter((id) => id != null);
            // Create category tree data source
            const categoryTreeDataSource = {
                loadRootNodes: async () => {
                    const result = await this.skillCategoryDataAccessor.query({
                        skip: 0,
                        take: 1000,
                        filter: {
                            field: 'parentId',
                            operator: { type: 'isEmpty' },
                            value: true,
                        },
                        sort: [{ field: 'title', dir: 'asc' }],
                    });
                    return (result.items || []).map((item) => ({
                        id: item.id,
                        title: item.title || item.name,
                        description: item.description || '',
                        parentId: item.parentId,
                        childrenCount: item.childrenCount || 0,
                    }));
                },
                loadChildNodes: async (parentId) => {
                    const result = await this.skillCategoryDataAccessor.query({
                        skip: 0,
                        take: 1000,
                        filter: {
                            field: 'parentId',
                            operator: { type: 'equal' },
                            value: parentId,
                        },
                        sort: [{ field: 'title', dir: 'asc' }],
                    });
                    return (result.items || []).map((item) => ({
                        id: item.id,
                        title: item.title || item.name,
                        description: item.description || '',
                        parentId: item.parentId,
                        childrenCount: item.childrenCount || 0,
                    }));
                },
                searchNodes: async (searchValue) => {
                    const result = await this.skillCategoryDataAccessor.query({
                        skip: 0,
                        take: 1000,
                        filter: {
                            filters: [
                                {
                                    field: 'title',
                                    operator: { type: 'contains' },
                                    value: searchValue,
                                },
                                {
                                    field: 'name',
                                    operator: { type: 'contains' },
                                    value: searchValue,
                                },
                            ],
                            logic: 'or',
                        },
                    });
                    return (result.items || []).map((item) => ({
                        id: item.id,
                        title: item.title || item.name,
                        description: item.description || '',
                        parentId: item.parentId,
                        childrenCount: item.childrenCount || 0,
                    }));
                },
            };
            const result = await this.entityDataSelectorService.open({
                entity: entityDef,
                title: 'Select Skills',
                allowMultiple: true,
                selectedItemIds: selectedItemIds.length > 0 ? selectedItemIds : undefined,
                columns: ['title', 'description'],
                showCategoryFilter: false,
                categoryFilter: {
                    title: 'Categories',
                    dataSource: categoryTreeDataSource,
                    filterField: 'categoryIds',
                    filterOperator: 'contains',
                    width: '350px',
                },
            });
            if (result && result.items && result.items.length > 0) {
                // Update selected skills
                this.selectedSkills.set(result.items);
                // Emit skill IDs change
                const skillIds = result.items.map((item) => item.id).filter((id) => id != null);
                this.skillIdsChange.emit(skillIds);
            }
        }
        catch (error) {
            console.error('Error opening skill selector:', error);
        }
    }
    /**
     * Remove a skill from selection
     */
    handleRemoveSkill(skillId) {
        const currentSkills = this.selectedSkills();
        const updatedSkills = currentSkills.filter((skill) => skill.id !== skillId);
        this.selectedSkills.set(updatedSkills);
        // Remove skill data from matrix value
        const currentMatrixData = this.value();
        const updatedMatrixData = { ...currentMatrixData };
        delete updatedMatrixData[skillId];
        // Emit updated matrix data
        this.valueChange.emit(updatedMatrixData);
        // Emit skill IDs change
        const skillIds = updatedSkills.map((skill) => skill.id).filter((id) => id != null);
        this.skillIdsChange.emit(skillIds);
    }
    /**
     * Handle row change event from spreadsheet (add/remove)
     */
    handleRowChange(event) {
        if (event.type === 'remove') {
            // Remove skill from selection
            this.handleRemoveSkill(event.rowId);
        }
        // Note: 'add' type shouldn't happen in fixed mode, but if it does, we can handle it here
    }
    static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: AXMLearningManagementSkillMatrixComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
    static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.19", type: AXMLearningManagementSkillMatrixComponent, isStandalone: true, selector: "axm-skill-matrix", inputs: { titles: { classPropertyName: "titles", publicName: "titles", isSignal: true, isRequired: false, transformFunction: null }, value: { classPropertyName: "value", publicName: "value", isSignal: true, isRequired: false, transformFunction: null }, readonly: { classPropertyName: "readonly", publicName: "readonly", isSignal: true, isRequired: false, transformFunction: null }, skillIds: { classPropertyName: "skillIds", publicName: "skillIds", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { valueChange: "valueChange", cellChange: "cellChange", skillIdsChange: "skillIdsChange" }, host: { classAttribute: "axm-skill-matrix" }, ngImport: i0, template: "<div class=\"__container\">\n  <div class=\"__matrix-section\">\n    <div class=\"__matrix-header ax-sm\">\n      @if (!readonly()) {\n      <ax-button color=\"primary\"\n        [text]=\"'@learning-management:skills.components.skill-matrix.actions.choose-skills.title' | translate | async\"\n        (onClick)=\"handleSelectSkills()\" [disabled]=\"isLoadingSkillEntity()\">\n        <ax-icon icon=\"far fa-plus\"></ax-icon>\n      </ax-button>\n      }\n    </div>\n    @if (isLoading()) {\n    <div class=\"__loading\">\n      <span>{{ '@learning-management:skills.components.skill-matrix.messages.loading-skill-levels' | translate | async\n        }}</span>\n    </div>\n    } @else {\n    <axp-spreadsheet [title]=\"'Skill / Level'\" [columns]=\"spreadsheetColumns()\" [rowsInput]=\"spreadsheetRows()\"\n      [rowMode]=\"'fixed'\" [readonly]=\"readonly()\" [allowRemoveRows]=\"true\" [rowTitlePath]=\"'_skillTitle'\"\n      [rowDescriptionPath]=\"'_skillDescription'\" (cellChange)=\"handleCellChange($event)\"\n      (spreadsheetChange)=\"handleSpreadsheetChange($event)\" (rowChange)=\"handleRowChange($event)\"></axp-spreadsheet>\n    }\n  </div>\n</div>", styles: [".axm-skill-matrix{display:block;height:100%;width:100%}.axm-skill-matrix .__container,.axm-skill-matrix .__matrix-section{display:flex;flex-direction:column}.axm-skill-matrix .__matrix-header{margin-bottom:.75rem;display:flex;justify-content:flex-end}.axm-skill-matrix .__loading{display:flex;align-items:center;justify-content:center;padding:2rem;font-size:.875rem;line-height:1.25rem;--tw-text-opacity: 1;color:rgb(82 82 82 / var(--tw-text-opacity, 1))}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "component", type: AXPSpreadsheetComponent, selector: "axp-spreadsheet", inputs: ["title", "columns", "rowMode", "rowsInput", "rowsModel", "readonly", "emptyCellPlaceholder", "rowTitlePath", "rowDescriptionPath", "allowAddRows", "allowRemoveRows"], outputs: ["rowsModelChange", "cellChange", "rowChange", "spreadsheetChange"] }, { kind: "ngmodule", type: AXButtonModule }, { kind: "component", type: i1.AXButtonComponent, selector: "ax-button", inputs: ["disabled", "size", "tabIndex", "color", "look", "text", "toggleable", "selected", "iconOnly", "type", "loadingText"], outputs: ["onBlur", "onFocus", "onClick", "selectedChange", "toggleableChange", "lookChange", "colorChange", "disabledChange", "loadingTextChange"] }, { kind: "ngmodule", type: AXDecoratorModule }, { kind: "component", type: i2.AXDecoratorIconComponent, selector: "ax-icon", inputs: ["icon"] }, { kind: "ngmodule", type: AXTranslationModule }, { kind: "pipe", type: i3.AsyncPipe, name: "async" }, { kind: "pipe", type: i4.AXTranslatorPipe, name: "translate" }], changeDetection: i0.ChangeDetectionStrategy.OnPush, encapsulation: i0.ViewEncapsulation.None }); }
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: AXMLearningManagementSkillMatrixComponent, decorators: [{
            type: Component,
            args: [{ selector: 'axm-skill-matrix', standalone: true, imports: [
                        CommonModule,
                        AXPSpreadsheetComponent,
                        AXButtonModule,
                        AXDecoratorModule,
                        AXTranslationModule,
                    ], encapsulation: ViewEncapsulation.None, changeDetection: ChangeDetectionStrategy.OnPush, host: {
                        class: 'axm-skill-matrix',
                    }, template: "<div class=\"__container\">\n  <div class=\"__matrix-section\">\n    <div class=\"__matrix-header ax-sm\">\n      @if (!readonly()) {\n      <ax-button color=\"primary\"\n        [text]=\"'@learning-management:skills.components.skill-matrix.actions.choose-skills.title' | translate | async\"\n        (onClick)=\"handleSelectSkills()\" [disabled]=\"isLoadingSkillEntity()\">\n        <ax-icon icon=\"far fa-plus\"></ax-icon>\n      </ax-button>\n      }\n    </div>\n    @if (isLoading()) {\n    <div class=\"__loading\">\n      <span>{{ '@learning-management:skills.components.skill-matrix.messages.loading-skill-levels' | translate | async\n        }}</span>\n    </div>\n    } @else {\n    <axp-spreadsheet [title]=\"'Skill / Level'\" [columns]=\"spreadsheetColumns()\" [rowsInput]=\"spreadsheetRows()\"\n      [rowMode]=\"'fixed'\" [readonly]=\"readonly()\" [allowRemoveRows]=\"true\" [rowTitlePath]=\"'_skillTitle'\"\n      [rowDescriptionPath]=\"'_skillDescription'\" (cellChange)=\"handleCellChange($event)\"\n      (spreadsheetChange)=\"handleSpreadsheetChange($event)\" (rowChange)=\"handleRowChange($event)\"></axp-spreadsheet>\n    }\n  </div>\n</div>", styles: [".axm-skill-matrix{display:block;height:100%;width:100%}.axm-skill-matrix .__container,.axm-skill-matrix .__matrix-section{display:flex;flex-direction:column}.axm-skill-matrix .__matrix-header{margin-bottom:.75rem;display:flex;justify-content:flex-end}.axm-skill-matrix .__loading{display:flex;align-items:center;justify-content:center;padding:2rem;font-size:.875rem;line-height:1.25rem;--tw-text-opacity: 1;color:rgb(82 82 82 / var(--tw-text-opacity, 1))}\n"] }]
        }], ctorParameters: () => [], propDecorators: { titles: [{ type: i0.Input, args: [{ isSignal: true, alias: "titles", required: false }] }], value: [{ type: i0.Input, args: [{ isSignal: true, alias: "value", required: false }] }], readonly: [{ type: i0.Input, args: [{ isSignal: true, alias: "readonly", required: false }] }], skillIds: [{ type: i0.Input, args: [{ isSignal: true, alias: "skillIds", required: false }] }], valueChange: [{ type: i0.Output, args: ["valueChange"] }], cellChange: [{ type: i0.Output, args: ["cellChange"] }], skillIdsChange: [{ type: i0.Output, args: ["skillIdsChange"] }] } });

export { AXMLearningManagementSkillMatrixComponent as A };
//# sourceMappingURL=acorex-modules-learning-management-skill-matrix.component-BVVtpWD_.mjs.map
