import { NgComponentOutlet } from '@angular/common';
import * as i0 from '@angular/core';
import { isDevMode, input, signal, computed, effect, ViewEncapsulation, ChangeDetectionStrategy, Component, makeEnvironmentProviders, inject } from '@angular/core';
import { NgIconComponent, provideNgIconLoader, withCaching } from '@ng-icons/core';
import { zMergeClasses } from '@shival99/z-ui/utils';
import * as animatedIcons from 'ng-animated-icons';
import { ZIndexDbService } from '@shival99/z-ui/services';
import { cva } from 'class-variance-authority';
import { HttpClient } from '@angular/common/http';
import { from, switchMap, of, map, tap, catchError } from 'rxjs';

const ANIMATED_ICONS = animatedIcons;
const BROKEN_ANIMATED_ICON_EXPORTS = new Set(['AudioLinesIcon']);
const Z_ANIMATED_ICONS = Object.fromEntries(Object.entries(ANIMATED_ICONS).filter(([exportName]) => exportName.endsWith('Icon') && !BROKEN_ANIMATED_ICON_EXPORTS.has(exportName)).map(([exportName, icon]) => [toKebabIconName(exportName), icon]));
function getZAnimatedIconComponent(iconName) {
    return Z_ANIMATED_ICONS[iconName] ?? null;
}
function toKebabIconName(exportName) {
    const iconName = exportName.endsWith('Icon') ? exportName.slice(0, -4) : exportName;
    return iconName
        .replace(/([a-z])([0-9])/g, '$1-$2')
        .replace(/([0-9])([A-Z])/g, '$1-$2')
        .replace(/([a-z0-9])([A-Z])/g, '$1-$2')
        .toLowerCase();
}

const Z_ICON_CACHE_DB_NAME = 'ZIconCache';
const Z_ICON_CACHE_STORE = 'zIcons';
const zIconCacheDb = new ZIndexDbService({
    dbName: Z_ICON_CACHE_DB_NAME,
    version: 1,
    stores: [{ name: Z_ICON_CACHE_STORE, encrypt: !isDevMode() }],
    defaultStore: Z_ICON_CACHE_STORE,
});

const zIconSizeVariants = Object.fromEntries(Array.from({ length: 100 - 10 + 1 }, (_, index) => {
    const size = String(10 + index);
    return [size, `size-${size}`];
}));
const zIconVariants = cva('', {
    variants: {
        zSize: zIconSizeVariants,
    },
    defaultVariants: {
        zSize: '16',
    },
});

class ZIconComponent {
    class = input('', ...(ngDevMode ? [{ debugName: "class" }] : []));
    zType = input(...(ngDevMode ? [undefined, { debugName: "zType" }] : []));
    zAnimatedType = input(...(ngDevMode ? [undefined, { debugName: "zAnimatedType" }] : []));
    zAnimate = input(false, ...(ngDevMode ? [{ debugName: "zAnimate" }] : []));
    zAnimationTrigger = input('manual', ...(ngDevMode ? [{ debugName: "zAnimationTrigger" }] : []));
    zSize = input('16', ...(ngDevMode ? [{ debugName: "zSize" }] : []));
    zStrokeWidth = input(2, ...(ngDevMode ? [{ debugName: "zStrokeWidth" }] : []));
    zSvg = input('', ...(ngDevMode ? [{ debugName: "zSvg" }] : []));
    resolvedSvg = signal('', ...(ngDevMode ? [{ debugName: "resolvedSvg" }] : []));
    isHoverActive = signal(false, ...(ngDevMode ? [{ debugName: "isHoverActive" }] : []));
    isFocusActive = signal(false, ...(ngDevMode ? [{ debugName: "isFocusActive" }] : []));
    isTouchActive = signal(false, ...(ngDevMode ? [{ debugName: "isTouchActive" }] : []));
    normalizedSize = computed(() => {
        const size = this.zSize();
        if (size === null || size === undefined || size === '') {
            return '16';
        }
        return String(size);
    }, ...(ngDevMode ? [{ debugName: "normalizedSize" }] : []));
    _svgFetchError = signal('', ...(ngDevMode ? [{ debugName: "_svgFetchError" }] : []));
    zClasses = computed(() => zMergeClasses(zIconVariants({ zSize: this.zSize() }), this.class(), this.zStrokeWidth() === 0 ? 'stroke-none' : '', 'inline-flex shrink-0'), ...(ngDevMode ? [{ debugName: "zClasses" }] : []));
    animatedIcon = computed(() => {
        const animatedType = this.zAnimatedType();
        if (!animatedType) {
            return null;
        }
        return getZAnimatedIconComponent(animatedType);
    }, ...(ngDevMode ? [{ debugName: "animatedIcon" }] : []));
    animatedIconInputs = computed(() => ({
        animate: this.shouldAnimate(),
        color: 'currentColor',
        size: Number(this.normalizedSize()),
        strokeWidth: this.zStrokeWidth(),
    }), ...(ngDevMode ? [{ debugName: "animatedIconInputs" }] : []));
    shouldAnimate = computed(() => {
        const trigger = this.zAnimationTrigger();
        if (trigger === 'always' || this.zAnimate()) {
            return true;
        }
        if (trigger === 'hover') {
            return this.isHoverActive() || this.isTouchActive();
        }
        if (trigger === 'focus') {
            return this.isFocusActive();
        }
        if (trigger === 'interaction') {
            return this.isHoverActive() || this.isFocusActive() || this.isTouchActive();
        }
        return false;
    }, ...(ngDevMode ? [{ debugName: "shouldAnimate" }] : []));
    constructor() {
        effect(onCleanup => {
            const svgInput = this.zSvg().trim();
            if (!svgInput) {
                this.resolvedSvg.set('');
                this._svgFetchError.set('');
                return;
            }
            if (this._isRawSvg(svgInput)) {
                this.resolvedSvg.set(this._normalizeCustomSvg(svgInput));
                this._svgFetchError.set('');
                return;
            }
            if (!this._isSvgPath(svgInput)) {
                this.resolvedSvg.set('');
                this._svgFetchError.set('Unsupported SVG input format.');
                return;
            }
            const controller = new AbortController();
            onCleanup(() => controller.abort());
            const cacheKey = `zsvg:path:${svgInput}`;
            void zIconCacheDb
                .get(cacheKey, { storeName: Z_ICON_CACHE_STORE })
                .then(cachedSvg => {
                if (controller.signal.aborted) {
                    return null;
                }
                if (cachedSvg && this._isRawSvg(cachedSvg.trim())) {
                    this.resolvedSvg.set(this._normalizeCustomSvg(cachedSvg));
                    this._svgFetchError.set('');
                    return null;
                }
                return fetch(svgInput, { signal: controller.signal }).then(response => {
                    if (!response.ok) {
                        throw new Error(`Failed to fetch SVG from "${svgInput}"`);
                    }
                    return response.text();
                });
            })
                .then(svgContent => {
                if (controller.signal.aborted || !svgContent) {
                    return;
                }
                if (!this._isRawSvg(svgContent.trim())) {
                    throw new Error(`Invalid SVG content loaded from "${svgInput}"`);
                }
                const normalizedSvg = this._normalizeCustomSvg(svgContent);
                this.resolvedSvg.set(normalizedSvg);
                this._svgFetchError.set('');
                void zIconCacheDb.set(cacheKey, normalizedSvg, { storeName: Z_ICON_CACHE_STORE }).catch(console.error);
            })
                .catch(error => {
                if (controller.signal.aborted) {
                    return;
                }
                console.error('[z-icon] Failed to load zSvg path:', error);
                this.resolvedSvg.set('');
                this._svgFetchError.set('Unable to load SVG path.');
            });
        });
    }
    _isRawSvg(value) {
        return value.startsWith('<svg');
    }
    setHoverActive(isActive) {
        this.isHoverActive.set(isActive);
    }
    setFocusActive(isActive) {
        this.isFocusActive.set(isActive);
    }
    setTouchActive(isActive) {
        this.isTouchActive.set(isActive);
    }
    _isSvgPath(value) {
        return value.endsWith('.svg') || value.includes('/');
    }
    _normalizeCustomSvg(svg) {
        try {
            const parser = new DOMParser();
            const doc = parser.parseFromString(svg, 'image/svg+xml');
            const svgEl = doc.documentElement;
            if (svgEl.tagName.toLowerCase() !== 'svg') {
                return svg;
            }
            const width = svgEl.getAttribute('width');
            const height = svgEl.getAttribute('height');
            if (!svgEl.getAttribute('viewBox') &&
                width &&
                height &&
                !Number.isNaN(Number(width)) &&
                !Number.isNaN(Number(height))) {
                svgEl.setAttribute('viewBox', `0 0 ${width} ${height}`);
            }
            svgEl.removeAttribute('width');
            svgEl.removeAttribute('height');
            const allNodes = [svgEl, ...Array.from(svgEl.querySelectorAll('*'))];
            allNodes.forEach(node => {
                const fill = node.getAttribute('fill');
                if (fill && fill !== 'none' && fill !== 'currentColor') {
                    node.setAttribute('fill', 'currentColor');
                }
                const stroke = node.getAttribute('stroke');
                if (stroke && stroke !== 'none' && stroke !== 'currentColor') {
                    node.setAttribute('stroke', 'currentColor');
                }
                if (node.hasAttribute('stroke-width')) {
                    node.removeAttribute('stroke-width');
                    const currentStyle = node.getAttribute('style') ?? '';
                    const normalizedStyle = currentStyle.trim();
                    const strokeWidthStyle = 'stroke-width: var(--ng-icon__stroke-width, 2)';
                    node.setAttribute('style', normalizedStyle ? `${normalizedStyle}; ${strokeWidthStyle}` : strokeWidthStyle);
                }
            });
            return svgEl.outerHTML;
        }
        catch {
            return svg;
        }
    }
    static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.0.9", ngImport: i0, type: ZIconComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
    static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.0.9", type: ZIconComponent, isStandalone: true, selector: "z-icon, [z-icon]", inputs: { class: { classPropertyName: "class", publicName: "class", isSignal: true, isRequired: false, transformFunction: null }, zType: { classPropertyName: "zType", publicName: "zType", isSignal: true, isRequired: false, transformFunction: null }, zAnimatedType: { classPropertyName: "zAnimatedType", publicName: "zAnimatedType", isSignal: true, isRequired: false, transformFunction: null }, zAnimate: { classPropertyName: "zAnimate", publicName: "zAnimate", isSignal: true, isRequired: false, transformFunction: null }, zAnimationTrigger: { classPropertyName: "zAnimationTrigger", publicName: "zAnimationTrigger", isSignal: true, isRequired: false, transformFunction: null }, zSize: { classPropertyName: "zSize", publicName: "zSize", isSignal: true, isRequired: false, transformFunction: null }, zStrokeWidth: { classPropertyName: "zStrokeWidth", publicName: "zStrokeWidth", isSignal: true, isRequired: false, transformFunction: null }, zSvg: { classPropertyName: "zSvg", publicName: "zSvg", isSignal: true, isRequired: false, transformFunction: null } }, host: { listeners: { "mouseenter": "setHoverActive(true)", "mouseleave": "setHoverActive(false)", "focusin": "setFocusActive(true)", "focusout": "setFocusActive(false)", "touchstart": "setTouchActive(true)", "touchend": "setTouchActive(false)" }, properties: { "class": "zClasses()", "style.width": "normalizedSize() + \"px\"", "style.height": "normalizedSize() + \"px\"" } }, ngImport: i0, template: "@if (animatedIcon()) {\n  <ng-container [ngComponentOutlet]=\"animatedIcon()\" [ngComponentOutletInputs]=\"animatedIconInputs()\" />\n} @else if (resolvedSvg()) {\n  <ng-icon [svg]=\"resolvedSvg()\" [size]=\"normalizedSize()\" [strokeWidth]=\"zStrokeWidth()\" />\n} @else if (!zSvg()) {\n  <ng-icon [name]=\"zType()\" [size]=\"normalizedSize()\" [strokeWidth]=\"zStrokeWidth()\" />\n}\n", dependencies: [{ kind: "component", type: NgIconComponent, selector: "ng-icon", inputs: ["name", "svg", "size", "strokeWidth", "color"] }, { kind: "directive", type: NgComponentOutlet, selector: "[ngComponentOutlet]", inputs: ["ngComponentOutlet", "ngComponentOutletInputs", "ngComponentOutletInjector", "ngComponentOutletEnvironmentInjector", "ngComponentOutletContent", "ngComponentOutletNgModule"], exportAs: ["ngComponentOutlet"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush, encapsulation: i0.ViewEncapsulation.None });
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.9", ngImport: i0, type: ZIconComponent, decorators: [{
            type: Component,
            args: [{ selector: 'z-icon, [z-icon]', imports: [NgIconComponent, NgComponentOutlet], standalone: true, changeDetection: ChangeDetectionStrategy.OnPush, encapsulation: ViewEncapsulation.None, host: {
                        '[class]': 'zClasses()',
                        '[style.width]': 'normalizedSize() + "px"',
                        '[style.height]': 'normalizedSize() + "px"',
                        '(mouseenter)': 'setHoverActive(true)',
                        '(mouseleave)': 'setHoverActive(false)',
                        '(focusin)': 'setFocusActive(true)',
                        '(focusout)': 'setFocusActive(false)',
                        '(touchstart)': 'setTouchActive(true)',
                        '(touchend)': 'setTouchActive(false)',
                    }, template: "@if (animatedIcon()) {\n  <ng-container [ngComponentOutlet]=\"animatedIcon()\" [ngComponentOutletInputs]=\"animatedIconInputs()\" />\n} @else if (resolvedSvg()) {\n  <ng-icon [svg]=\"resolvedSvg()\" [size]=\"normalizedSize()\" [strokeWidth]=\"zStrokeWidth()\" />\n} @else if (!zSvg()) {\n  <ng-icon [name]=\"zType()\" [size]=\"normalizedSize()\" [strokeWidth]=\"zStrokeWidth()\" />\n}\n" }]
        }], ctorParameters: () => [], propDecorators: { class: [{ type: i0.Input, args: [{ isSignal: true, alias: "class", required: false }] }], zType: [{ type: i0.Input, args: [{ isSignal: true, alias: "zType", required: false }] }], zAnimatedType: [{ type: i0.Input, args: [{ isSignal: true, alias: "zAnimatedType", required: false }] }], zAnimate: [{ type: i0.Input, args: [{ isSignal: true, alias: "zAnimate", required: false }] }], zAnimationTrigger: [{ type: i0.Input, args: [{ isSignal: true, alias: "zAnimationTrigger", required: false }] }], zSize: [{ type: i0.Input, args: [{ isSignal: true, alias: "zSize", required: false }] }], zStrokeWidth: [{ type: i0.Input, args: [{ isSignal: true, alias: "zStrokeWidth", required: false }] }], zSvg: [{ type: i0.Input, args: [{ isSignal: true, alias: "zSvg", required: false }] }] } });

const Z_ICONS = {};

/**
 * Normalizes Sax SVG to use currentColor and CSS variable for stroke-width.
 * This allows the icon to inherit color and strokeWidth from ng-icon props.
 */
function normalizeSaxSvg(svg) {
    const cssVar = 'style="stroke-width: var(--ng-icon__stroke-width, 2)"';
    const normalized = svg.replace(/fill="#292D32"/gi, 'fill="currentColor"');
    return normalized.replace(/stroke-width="[^"]*"/gi, cssVar);
}
/**
 * Normalizes Lucide SVG to use CSS variable for stroke-width.
 * This allows ng-icon strokeWidth prop to work correctly.
 * Replaces hardcoded stroke-width with var(--ng-icon__stroke-width, 2).
 */
function normalizeLucideSvg(svg) {
    const cssVar = 'style="stroke-width: var(--ng-icon__stroke-width, 2)"';
    return svg.replace(/stroke-width="[^"]*"/gi, cssVar);
}
function getFallbackIcon(name) {
    const icon = Z_ICONS[name];
    if (icon) {
        // console.warn(`[ZIcon] Using bundled fallback for "${name}"`);
        return icon;
    }
    return '';
}
/**
 * Converts ng-icons icon name to Lucide CDN format.
 * Examples:
 * - lucideArrowLeft -> arrow-left
 * - lucideAlertCircle -> alert-circle
 * - lucideTrash2 -> trash-2
 * - lucideGrid3x3 -> grid-3-x-3
 */
function convertLucideIconName(name) {
    return name
        .replace(/^lucide/, '')
        .replace(/([A-Z])/g, '-$1')
        .replace(/(\d+)/g, '-$1')
        .replace(/(\d)([a-z])/g, '$1-$2')
        .toLowerCase()
        .replace(/^-/, '')
        .replace(/--+/g, '-');
}
/**
 * Converts ng-icons Sax icon name to CDN format.
 * Examples:
 * - saxCloudChangeBold -> bold/cloud-change
 * - saxPauseBold -> bold/pause
 * - saxRefreshBold -> bold/refresh
 * - saxHomeOutline -> outline/home
 * - saxUserLinear -> linear/user
 */
function convertIconSaxIconName(name) {
    let iconPart = name.replace(/^sax/, '');
    // Extract style suffix (Bold, Outline, Linear, Bulk, Broken, TwoTone)
    const styleMatch = iconPart.match(/(Bold|Outline|Linear|Bulk|Broken|TwoTone)$/i);
    if (!styleMatch) {
        return null;
    }
    const style = styleMatch[1].toLowerCase();
    const styleFolder = style === 'twotone' ? 'twotone' : style;
    iconPart = iconPart.replace(/(Bold|Outline|Linear|Bulk|Broken|TwoTone)$/i, '');
    const iconName = iconPart
        .replace(/([A-Z])/g, '-$1')
        .replace(/(\d+)/g, '-$1')
        .toLowerCase()
        .replace(/^-/, '')
        .replace(/--+/g, '-');
    return { style: styleFolder, iconName };
}
const LUCIDE_CDN_URL = 'https://cdn.jsdelivr.net/npm/lucide-static@latest/icons';
const SAX_CDN_URL = 'https://cdn.jsdelivr.net/gh/placetopay-org/iconsax-vue@main/src/Base';
/**
 * Provides hybrid icon loading from CDN with fallback to bundled icons:
 * - Primary: Load icons from CDN (Lucide & Iconsax)
 * - Fallback: Use bundled icons from Z_ICONS if CDN fails
 *
 * @example
 * ```typescript
 * // app.config.ts
 * providers: [
 *   provideHttpClient(),
 *   provideZIconLoader(),
 * ]
 * ```
 */
function loadWithCache(name, url, http, normalizer) {
    return from(zIconCacheDb.get(name, { storeName: Z_ICON_CACHE_STORE })).pipe(switchMap(cached => {
        if (cached) {
            return of(cached);
        }
        return http.get(url, { responseType: 'text' }).pipe(map(normalizer), tap(svg => {
            void zIconCacheDb.set(name, svg, { storeName: Z_ICON_CACHE_STORE });
        }), catchError(error => {
            console.error(`[ZIcon] Failed to load "${name}" from ${url}`, error);
            return of(getFallbackIcon(name));
        }));
    }), catchError(() => of(getFallbackIcon(name))));
}
function provideZIconLoader() {
    return makeEnvironmentProviders([
        provideNgIconLoader(name => {
            const http = inject(HttpClient);
            if (name.startsWith('sax')) {
                const parsed = convertIconSaxIconName(name);
                if (!parsed) {
                    console.warn(`[ZIcon] Invalid Sax icon name: "${name}"`);
                    return of(getFallbackIcon(name));
                }
                const url = `${SAX_CDN_URL}/${parsed.style}/${parsed.iconName}.svg`;
                return loadWithCache(name, url, http, normalizeSaxSvg);
            }
            if (name.startsWith('lucide')) {
                const iconName = convertLucideIconName(name);
                const url = `${LUCIDE_CDN_URL}/${iconName}.svg`;
                return loadWithCache(name, url, http, normalizeLucideSvg);
            }
            // console.warn(`[ZIcon] Unknown icon: "${name}"`);
            return of(getFallbackIcon(name));
        }, withCaching()),
    ]);
}

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

export { ZIconComponent, Z_ANIMATED_ICONS, Z_ICONS, provideZIconLoader, zIconVariants };
//# sourceMappingURL=shival99-z-ui-components-z-icon.mjs.map
