// #region Imports
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
    var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
    if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
    else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
    return c > 3 && r && Object.defineProperty(target, key, r), r;
};
var __metadata = (this && this.__metadata) || function (k, v) {
    if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
};
import { HTMLElementEventEmitter } from '@breadstone/mosaik-elements';
import { Emit } from '../../../../events/Decorators/EmitDecorator';
import { Disableable } from '../../../Behaviors/Disableable';
import { Themeable } from '../../../Behaviors/Themeable';
import { Attribute } from '../../../Decorators/AttributeDecorator';
import { Component } from '../../../Decorators/ComponentDecorator';
import { Property } from '../../../Decorators/PropertyDecorator';
import { CustomElement } from '../../Abstracts/CustomElement';
import { ButtonElement } from '../../Buttons/Button/ButtonElement';
import { TextBoxElement } from '../../Inputs/TextBox/TextBoxElement';
import { ChipElement } from '../Chip/ChipElement';
import { fontEditorElementTemplate } from './FontEditorElementTemplate';
import { LocalFontProvider } from './Providers/LocalFontProvider';
import { fontEditorElementCosmopolitanStyle } from './Themes/FontEditorElement.Cosmopolitan';
import { fontEditorElementJoyStyle } from './Themes/FontEditorElement.Joy';
import { fontEditorElementMemphisStyle } from './Themes/FontEditorElement.Memphis';
// #endregion
/**
 * A font editor component that allows users to browse, search, and select fonts
 * from various providers with filtering by alphabet, category, and search text.
 *
 * @name FontEditor
 * @element mosaik-font-editor
 *
 * @description
 * The FontEditor component provides a comprehensive font selection experience:
 * - Alphabet buttons (A-Z) for quick filtering
 * - Category chips for filtering by font type
 * - Search input for finding fonts by name
 * - Preview text with selected font
 * - Font list with visual samples
 * - Support for multiple font providers (local, Google, Adobe, custom)
 *
 * @category Media
 *
 * @fires fontSelected {FontSelectedEvent} - Fired when a font is selected
 * @fires fontChanged {FontChangedEvent} - Fired when the selected font changes
 *
 * @csspart root - The root container
 * @csspart preview - The preview section
 * @csspart preview-text - The preview text
 * @csspart search - The search input
 * @csspart filters - The filters container
 * @csspart categories - The category filter container
 * @csspart alphabet - The alphabet filter container
 * @csspart alphabet-button - An alphabet filter button
 * @csspart list-container - The font list container
 * @csspart font-item - A font list item
 * @csspart font-name - The font name in a list item
 * @csspart font-category - The font category in a list item
 * @csspart loading - The loading indicator
 * @csspart empty - The empty state message
 *
 * @public
 */
let FontEditorElement = class FontEditorElement extends Disableable(Themeable(CustomElement)) {
    // #region Fields
    _selected;
    _fontChanged;
    _selectedFont;
    _previewText;
    _searchText;
    _selectedCategory;
    _selectedLetter;
    _showPreview;
    _showAlphabetFilter;
    _showCategoryFilter;
    _showSearch;
    _showCollections;
    _providers;
    _collections;
    _allFonts;
    _fonts;
    _loading;
    _availableLetters;
    // #endregion
    // #region Ctor
    /**
     * Constructs a new instance of the FontEditorElement class.
     *
     * @public
     */
    constructor() {
        super();
        this._selected = new HTMLElementEventEmitter(this, 'fontSelected');
        this._fontChanged = new HTMLElementEventEmitter(this, 'fontChanged');
        this._selectedFont = null;
        this._previewText = 'The quick brown fox jumps over the lazy dog.';
        this._searchText = '';
        this._selectedCategory = null;
        this._selectedLetter = null;
        this._showPreview = true;
        this._showAlphabetFilter = true;
        this._showCategoryFilter = true;
        this._showSearch = true;
        this._showCollections = false;
        this._providers = [new LocalFontProvider()];
        this._collections = [];
        this._allFonts = [];
        this._fonts = [];
        this._loading = false;
        this._availableLetters = [];
    }
    // #endregion
    // #region Properties
    /**
     * Returns the `{@link is}` property.
     * The `{@link is}` property represents natural name of this element.
     *
     * @public
     * @static
     * @readonly
     */
    static get is() {
        return 'mosaik-font-editor';
    }
    /**
     * Gets or sets the currently selected font.
     *
     * @public
     */
    get selectedFont() {
        return this._selectedFont;
    }
    set selectedFont(value) {
        if (this._selectedFont !== value) {
            this._selectedFont = value;
            this.requestUpdate('selectedFont');
        }
    }
    /**
     * Gets or sets the text to display in the preview.
     *
     * @public
     * @attr
     */
    get previewText() {
        return this._previewText;
    }
    set previewText(value) {
        if (this._previewText !== value) {
            this._previewText = value;
            this.requestUpdate('previewText');
        }
    }
    /**
     * Gets or sets the current search text.
     *
     * @public
     * @attr
     */
    get searchText() {
        return this._searchText;
    }
    set searchText(value) {
        if (this._searchText !== value) {
            this._searchText = value;
            this.requestUpdate('searchText');
        }
    }
    /**
     * Gets or sets the selected category filter.
     *
     * @public
     * @attr
     */
    get selectedCategory() {
        return this._selectedCategory;
    }
    set selectedCategory(value) {
        if (this._selectedCategory !== value) {
            this._selectedCategory = value;
            this.requestUpdate('selectedCategory');
        }
    }
    /**
     * Gets or sets the selected starting letter filter.
     *
     * @public
     * @attr
     */
    get selectedLetter() {
        return this._selectedLetter;
    }
    set selectedLetter(value) {
        if (this._selectedLetter !== value) {
            this._selectedLetter = value;
            this.requestUpdate('selectedLetter');
        }
    }
    /**
     * Gets or sets whether to show the preview section.
     *
     * @public
     */
    get showPreview() {
        return this._showPreview;
    }
    set showPreview(value) {
        if (this._showPreview !== value) {
            this._showPreview = value;
            this.requestUpdate('showPreview');
        }
    }
    /**
     * Gets or sets whether to show the alphabet filter.
     *
     * @public
     */
    get showAlphabetFilter() {
        return this._showAlphabetFilter;
    }
    set showAlphabetFilter(value) {
        if (this._showAlphabetFilter !== value) {
            this._showAlphabetFilter = value;
            this.requestUpdate('showAlphabetFilter');
        }
    }
    /**
     * Gets or sets whether to show the category filter.
     *
     * @public
     */
    get showCategoryFilter() {
        return this._showCategoryFilter;
    }
    set showCategoryFilter(value) {
        if (this._showCategoryFilter !== value) {
            this._showCategoryFilter = value;
            this.requestUpdate('showCategoryFilter');
        }
    }
    /**
     * Gets or sets whether to show the search input.
     *
     * @public
     */
    get showSearch() {
        return this._showSearch;
    }
    set showSearch(value) {
        if (this._showSearch !== value) {
            this._showSearch = value;
            this.requestUpdate('showSearch');
        }
    }
    /**
     * Gets or sets whether to show the collections panel.
     *
     * @public
     */
    get showCollections() {
        return this._showCollections;
    }
    set showCollections(value) {
        if (this._showCollections !== value) {
            this._showCollections = value;
            this.requestUpdate('showCollections');
        }
    }
    /**
     * Gets or sets the available font providers.
     *
     * @public
     */
    get providers() {
        return this._providers;
    }
    set providers(value) {
        if (this._providers !== value) {
            this._providers = value;
            void this.loadFonts();
        }
    }
    /**
     * Gets or sets the font collections.
     *
     * @public
     */
    get collections() {
        return this._collections;
    }
    set collections(value) {
        if (this._collections !== value) {
            this._collections = value;
            this.requestUpdate('collections');
        }
    }
    /**
     * Called when a font is selected.
     * Provides reference to `{@link IFontSelectedEventDetail}` as event detail.
     *
     * @public
     * @readonly
     * @eventProperty
     */
    get selected() {
        return this._selected;
    }
    /**
     * Called when the selected font changes.
     * Provides reference to `{@link IFontChangedEventDetail}` as event detail.
     *
     * @public
     * @readonly
     * @eventProperty
     */
    get fontChanged() {
        return this._fontChanged;
    }
    // #endregion
    // #region Properties (Additional)
    /**
     * Gets the fonts currently displayed.
     *
     * @public
     * @readonly
     */
    get fonts() {
        return this._fonts;
    }
    /**
     * Gets whether the component is loading.
     *
     * @public
     * @readonly
     */
    get loading() {
        return this._loading;
    }
    /**
     * Gets the available letters for filtering.
     *
     * @public
     * @readonly
     */
    get availableLetters() {
        return this._availableLetters;
    }
    // #endregion
    // #region Methods
    /**
     * @inheritdoc
     */
    connectedCallback() {
        super.connectedCallback();
        // Load fonts on first connect
        void this.loadFonts();
    }
    /**
     * Adds a font provider.
     *
     * @param provider - The provider to add.
     */
    addProvider(provider) {
        this._providers.push(provider);
        void this.loadFonts();
    }
    /**
     * Removes a font provider.
     *
     * @param providerId - The ID of the provider to remove.
     */
    removeProvider(providerId) {
        const index = this._providers.findIndex((p) => p.name === providerId);
        if (index !== -1) {
            this._providers.splice(index, 1);
            void this.loadFonts();
        }
    }
    /**
     * Loads fonts from all providers.
     */
    async loadFonts() {
        this._loading = true;
        this.requestUpdate();
        try {
            const allFonts = [];
            const abortController = new AbortController();
            for (const provider of this._providers) {
                const request = {
                    searchText: this.searchText || undefined,
                    category: this.selectedCategory ?? undefined,
                    startingLetter: this.selectedLetter ?? undefined,
                    signal: abortController.signal
                };
                const response = await provider.fetchFonts(request);
                allFonts.push(...response.fonts);
            }
            // Sort alphabetically
            this._allFonts = allFonts.sort((a, b) => a.family.localeCompare(b.family));
            this._fonts = [...this._allFonts];
            // Update available letters
            this._availableLetters = this.computeAvailableLetters();
            this.requestUpdate();
        }
        catch (error) {
            console.error('Error loading fonts:', error);
            this._fonts = [];
            this._availableLetters = [];
        }
        finally {
            this._loading = false;
            this.requestUpdate();
        }
    }
    /**
     * Computes the available letters based on loaded fonts.
     */
    computeAvailableLetters() {
        const letters = new Set();
        for (const font of this._allFonts) {
            const firstLetter = font.family.charAt(0).toUpperCase();
            if ((/[A-Z]/).test(firstLetter)) {
                letters.add(firstLetter);
            }
        }
        return Array.from(letters).sort();
    }
    /**
     * Filters fonts by letter.
     *
     * @param letter - The letter to filter by, or null for all.
     */
    filterByLetter(letter) {
        this.selectedLetter = letter;
        this.applyFilters();
    }
    /**
     * Filters fonts by category.
     *
     * @param category - The category to filter by, or null for all.
     */
    filterByCategory(category) {
        this.selectedCategory = category;
        this.applyFilters();
    }
    /**
     * Filters fonts by search text.
     *
     * @param text - The search text.
     */
    filterBySearch(text) {
        this.searchText = text;
        this.applyFilters();
    }
    /**
     * Applies all active filters.
     */
    applyFilters() {
        let filtered = [...this._allFonts];
        // Apply letter filter
        if (this.selectedLetter) {
            const letter = this.selectedLetter.toLowerCase();
            filtered = filtered.filter((font) => font.family.toLowerCase().startsWith(letter));
        }
        // Apply category filter
        if (this.selectedCategory) {
            filtered = filtered.filter((font) => font.category === this.selectedCategory);
        }
        // Apply search filter
        if (this.searchText) {
            const search = this.searchText.toLowerCase();
            filtered = filtered.filter((font) => font.family.toLowerCase().includes(search));
        }
        this._fonts = filtered;
        this.requestUpdate();
    }
    /**
     * Selects a font.
     *
     * @param font - The font to select.
     */
    selectFont(font) {
        const previousFont = this.selectedFont;
        this.selectedFont = font;
        this.emitSelect(font);
        if (previousFont?.id !== font.id) {
            this.emitChange(font);
        }
        this.requestUpdate();
    }
    /**
     * Loads a font for preview.
     *
     * @param font - The font to load.
     */
    loadFont(font) {
        const provider = this._providers.find((p) => p.name === font.source);
        if (provider) {
            provider.loadFont(font);
        }
    }
    /**
     * Emits the select event.
     *
     * @private
     */
    emitSelect(font) {
        this._selected.emit({ font });
    }
    /**
     * Emits the change event.
     *
     * @private
     */
    emitChange(font) {
        this._fontChanged.emit({ font });
    }
};
__decorate([
    Property({ type: Object }),
    __metadata("design:type", Object),
    __metadata("design:paramtypes", [Object])
], FontEditorElement.prototype, "selectedFont", null);
__decorate([
    Attribute({ type: String }),
    __metadata("design:type", String),
    __metadata("design:paramtypes", [String])
], FontEditorElement.prototype, "previewText", null);
__decorate([
    Attribute({ type: String }),
    __metadata("design:type", String),
    __metadata("design:paramtypes", [String])
], FontEditorElement.prototype, "searchText", null);
__decorate([
    Attribute({ type: String }),
    __metadata("design:type", Object),
    __metadata("design:paramtypes", [Object])
], FontEditorElement.prototype, "selectedCategory", null);
__decorate([
    Attribute({ type: String }),
    __metadata("design:type", Object),
    __metadata("design:paramtypes", [Object])
], FontEditorElement.prototype, "selectedLetter", null);
__decorate([
    Property({
        type: Boolean,
        useDefault: true
    }),
    __metadata("design:type", Boolean),
    __metadata("design:paramtypes", [Boolean])
], FontEditorElement.prototype, "showPreview", null);
__decorate([
    Property({
        type: Boolean,
        useDefault: true
    }),
    __metadata("design:type", Boolean),
    __metadata("design:paramtypes", [Boolean])
], FontEditorElement.prototype, "showAlphabetFilter", null);
__decorate([
    Property({
        type: Boolean,
        useDefault: true
    }),
    __metadata("design:type", Boolean),
    __metadata("design:paramtypes", [Boolean])
], FontEditorElement.prototype, "showCategoryFilter", null);
__decorate([
    Property({
        type: Boolean,
        useDefault: true
    }),
    __metadata("design:type", Boolean),
    __metadata("design:paramtypes", [Boolean])
], FontEditorElement.prototype, "showSearch", null);
__decorate([
    Property({
        type: Boolean,
        useDefault: true
    }),
    __metadata("design:type", Boolean),
    __metadata("design:paramtypes", [Boolean])
], FontEditorElement.prototype, "showCollections", null);
__decorate([
    Property({ type: Array }),
    __metadata("design:type", Array),
    __metadata("design:paramtypes", [Array])
], FontEditorElement.prototype, "providers", null);
__decorate([
    Property({ type: Array }),
    __metadata("design:type", Array),
    __metadata("design:paramtypes", [Array])
], FontEditorElement.prototype, "collections", null);
__decorate([
    Emit({ eventName: 'fontSelected' }),
    __metadata("design:type", Object),
    __metadata("design:paramtypes", [])
], FontEditorElement.prototype, "selected", null);
__decorate([
    Emit({ eventName: 'fontChanged' }),
    __metadata("design:type", Object),
    __metadata("design:paramtypes", [])
], FontEditorElement.prototype, "fontChanged", null);
FontEditorElement = __decorate([
    Component({
        selector: 'mosaik-font-editor',
        template: fontEditorElementTemplate,
        themes: {
            joy: fontEditorElementJoyStyle,
            memphis: fontEditorElementMemphisStyle,
            cosmopolitan: fontEditorElementCosmopolitanStyle
        },
        imports: [
            ButtonElement,
            ChipElement,
            TextBoxElement
        ]
    }),
    __metadata("design:paramtypes", [])
], FontEditorElement);
export { FontEditorElement };
//# sourceMappingURL=FontEditorElement.js.map