/**
 * TyIcon Web Component
 * PORTED FROM: clj/ty/components/icon.cljs
 * SVG icon component with size variants and animations
 */
import { ensureStyles } from '../utils/styles.js';
import { iconStyles } from '../styles/icon.js';
import * as IconRegistry from '../utils/icon-registry.js';
/** Fallback SVG for missing icons - More visible to prevent layout shift */
const NOT_FOUND_ICON = `<svg xmlns="http://www.w3.org/2000/svg" 
      viewBox="0 0 512 512" 
      fill="currentColor" 
      opacity="0.2">
   <path d="M256 512A256 256 0 1 0 256 0a256 256 0 1 0 0 512z"/>
</svg>`;
/**
 * Ty Icon Component
 *
 * @example
 * ```html
 * <ty-icon name="check"></ty-icon>
 * <ty-icon name="spinner" spin></ty-icon>
 * <ty-icon name="heart" size="xl"></ty-icon>
 * ```
 */
export class TyIcon extends HTMLElement {
    constructor() {
        super();
        this._name = '';
        this._size = undefined;
        this._spin = false;
        this._pulse = false;
        this._tempo = undefined;
        this._watchId = null;
        /** Track currently rendered SVG to avoid unnecessary re-renders */
        this._currentSvg = '';
        const shadow = this.attachShadow({ mode: 'open' });
        ensureStyles(shadow, { css: iconStyles, id: 'ty-icon' });
        shadow.innerHTML = NOT_FOUND_ICON;
    }
    static get observedAttributes() {
        return ['name', 'size', 'spin', 'pulse', 'tempo'];
    }
    connectedCallback() {
        // Generate unique watch ID
        this._watchId = `ty-icon-${crypto.randomUUID()}`;
        // Watch for registry changes that affect this icon
        if (this._name) {
            IconRegistry.addWatcher(this._watchId, this._name, (changedIcons) => {
                // Re-render if our icon changed
                if (this._name && changedIcons.has(this._name)) {
                    this.render();
                }
            });
        }
        // Initial render
        this.render();
    }
    disconnectedCallback() {
        // Clean up watcher
        if (this._watchId) {
            IconRegistry.removeWatcher(this._watchId);
            this._watchId = null;
        }
    }
    attributeChangedCallback(name, oldValue, newValue) {
        if (oldValue === newValue)
            return;
        switch (name) {
            case 'name':
                if (this._name !== (newValue || '')) {
                    // Update watch when name changes
                    if (this._watchId) {
                        IconRegistry.removeWatcher(this._watchId);
                    }
                    this._name = newValue || '';
                    // Re-add watcher for new name
                    if (this._name && this.isConnected) {
                        this._watchId = `ty-icon-${crypto.randomUUID()}`;
                        IconRegistry.addWatcher(this._watchId, this._name, (changedIcons) => {
                            if (this._name && changedIcons.has(this._name)) {
                                this.render();
                            }
                        });
                    }
                }
                break;
            case 'size':
                this._size = newValue || undefined;
                break;
            case 'spin':
                this._spin = newValue !== null;
                break;
            case 'pulse':
                this._pulse = newValue !== null;
                break;
            case 'tempo':
                this._tempo = newValue || undefined;
                break;
        }
        this.updateClasses();
        this.render();
    }
    // Public API - Getters/Setters
    // NOTE: All setters trigger re-render to support property changes from frameworks like React
    get name() {
        return this._name;
    }
    set name(value) {
        if (this._name !== value) {
            this._name = value;
            this.setAttribute('name', value);
            this.render();
        }
    }
    get size() {
        return this._size;
    }
    set size(value) {
        if (this._size !== value) {
            this._size = value;
            if (value) {
                this.setAttribute('size', value);
            }
            else {
                this.removeAttribute('size');
            }
            this.updateClasses();
        }
    }
    get spin() {
        return this._spin;
    }
    set spin(value) {
        if (this._spin !== value) {
            this._spin = value;
            if (value) {
                this.setAttribute('spin', '');
            }
            else {
                this.removeAttribute('spin');
            }
            this.updateClasses();
        }
    }
    get pulse() {
        return this._pulse;
    }
    set pulse(value) {
        if (this._pulse !== value) {
            this._pulse = value;
            if (value) {
                this.setAttribute('pulse', '');
            }
            else {
                this.removeAttribute('pulse');
            }
            this.updateClasses();
        }
    }
    get tempo() {
        return this._tempo;
    }
    set tempo(value) {
        if (this._tempo !== value) {
            this._tempo = value;
            if (value) {
                this.setAttribute('tempo', value);
            }
            else {
                this.removeAttribute('tempo');
            }
            this.updateClasses();
        }
    }
    /** Build CSS classes for the host element */
    buildClasses() {
        const classes = [];
        // Size class
        if (this._size) {
            classes.push(`icon-${this._size}`);
        }
        // Animation classes
        if (this._spin) {
            classes.push('icon-spin');
        }
        if (this._pulse) {
            classes.push('icon-pulse');
        }
        // Tempo class
        if (this._tempo && (this._spin || this._pulse)) {
            classes.push(`icon-tempo-${this._tempo}`);
        }
        // Preserve user-added classes that don't conflict
        const currentClasses = this.className.split(/\s+/).filter(cls => {
            // Filter out component-managed classes
            return cls &&
                !cls.startsWith('icon-') &&
                cls !== 'icon-spin' &&
                cls !== 'icon-pulse';
        });
        return [...classes, ...currentClasses];
    }
    /** Update host element classes */
    updateClasses() {
        const newClasses = this.buildClasses().join(' ');
        if (this.className !== newClasses) {
            this.className = newClasses;
        }
    }
    /**
     * Render the icon SVG
     * Smart rendering strategy:
     * 1. Check memory registry (instant)
     * 2. If found in memory → render immediately
     * 3. If not in memory → show NOT_FOUND_ICON immediately (prevents empty state)
     * 4. Then check cache asynchronously and replace if found
     * 5. Only re-render if SVG actually changed
     */
    render() {
        if (!this._name) {
            this.renderSvg(NOT_FOUND_ICON);
            return;
        }
        // Fast path: Check memory registry first
        const memorySvg = IconRegistry.getIcon(this._name);
        if (memorySvg) {
            this.renderSvg(memorySvg);
            return;
        }
        this.renderSvg(NOT_FOUND_ICON);
        // Slow path: Check cache asynchronously
        // This will replace NOT_FOUND_ICON if icon is found in cache
        /* IconRegistry.getCachedIcon(this._name).then(cachedSvg => {
          if (cachedSvg) {
            // Found in cache - replace NOT_FOUND_ICON with cached icon
            this.renderSvg(cachedSvg)
          }
          // If not in cache, NOT_FOUND_ICON already showing (no change needed)
        }).catch(err => {
          console.warn(`[ty-icon] Failed to load icon "${this._name}":`, err)
          // NOT_FOUND_ICON already showing (no change needed)
        })
        */
    }
    /**
     * Actually render SVG to shadow DOM
     * Only updates if content changed to prevent unnecessary reflows
     */
    renderSvg(svg) {
        // Only render if content actually changed
        if (this._currentSvg === svg) {
            return;
        }
        const shadow = this.shadowRoot;
        shadow.innerHTML = svg;
        this._currentSvg = svg;
    }
}
// Register the custom element
if (!customElements.get('ty-icon')) {
    customElements.define('ty-icon', TyIcon);
}
// Export for use in other modules
export { IconRegistry };
//# sourceMappingURL=icon.js.map