import * as i0 from '@angular/core';
import { Injectable, InjectionToken, input, booleanAttribute, output, signal, computed, inject, HostListener, Directive, NgModule } from '@angular/core';
import { Subject } from 'rxjs';
import { LocationStrategy } from '@angular/common';
import { Router, ActivatedRoute, NavigationEnd } from '@angular/router';
import { injectSiTranslateService } from '@siemens/element-translate-ng/translate';
import { takeUntil, filter } from 'rxjs/operators';

/**
 * Copyright (c) Siemens 2016 - 2026
 * SPDX-License-Identifier: MIT
 */
class SiLinkActionService {
    actionSubject = new Subject();
    /**
     * Observable which emits the link and param to run the action on.
     *
     * @defaultValue this.actionSubject.asObservable()
     */
    action$ = this.actionSubject.asObservable();
    /**
     * Emit a new link and param pair to run the action on.
     */
    emit(link, param) {
        this.actionSubject.next({ link, param });
    }
    static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.0.8", ngImport: i0, type: SiLinkActionService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
    static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.0.8", ngImport: i0, type: SiLinkActionService });
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.8", ngImport: i0, type: SiLinkActionService, decorators: [{
            type: Injectable
        }] });

/**
 * Copyright (c) Siemens 2016 - 2026
 * SPDX-License-Identifier: MIT
 */
const SI_LINK_DEFAULT_NAVIGATION_EXTRA = new InjectionToken('SI_LINK_DEFAULT_NAVIGATION_EXTRA');
class SiLinkDirective {
    siLink = input(...(ngDevMode ? [undefined, { debugName: "siLink" }] : []));
    siLinkDefaultTarget = input(...(ngDevMode ? [undefined, { debugName: "siLinkDefaultTarget" }] : []));
    actionParam = input(...(ngDevMode ? [undefined, { debugName: "actionParam" }] : []));
    activeClass = input(...(ngDevMode ? [undefined, { debugName: "activeClass" }] : []));
    /** @defaultValue false */
    exactMatch = input(false, { ...(ngDevMode ? { debugName: "exactMatch" } : {}), transform: booleanAttribute });
    /**
     * Type for `aria-current` to set if routerLink is active.
     */
    ariaCurrent = input(...(ngDevMode ? [undefined, { debugName: "ariaCurrent" }] : []));
    activeChange = output();
    href = signal(undefined, ...(ngDevMode ? [{ debugName: "href" }] : []));
    target = signal(undefined, ...(ngDevMode ? [{ debugName: "target" }] : []));
    title = signal(undefined, ...(ngDevMode ? [{ debugName: "title" }] : []));
    isAriaCurrent = computed(() => this.active() ? (this.ariaCurrent() ?? 'true') : undefined, ...(ngDevMode ? [{ debugName: "isAriaCurrent" }] : []));
    /** @defaultValue false */
    active = signal(false, ...(ngDevMode ? [{ debugName: "active" }] : []));
    destroyer = new Subject();
    router = inject(Router, { optional: true });
    activatedRoute = inject(ActivatedRoute, { optional: true });
    locationStrategy = inject(LocationStrategy, { optional: true });
    translateService = injectSiTranslateService();
    actionService = inject(SiLinkActionService, { optional: true });
    defaultNavigationExtra = inject(SI_LINK_DEFAULT_NAVIGATION_EXTRA, { optional: true });
    get urlTree() {
        const link = this.siLink().link;
        return this.router.createUrlTree(Array.isArray(link) ? link : [link], this.navigationExtras);
    }
    get navigationExtras() {
        return {
            relativeTo: this.activatedRoute,
            preserveFragment: true,
            queryParamsHandling: 'merge',
            ...this.defaultNavigationExtra,
            ...this.siLink().navigationExtras
        };
    }
    ngOnDestroy() {
        this.destroyer.next();
        this.destroyer.complete();
    }
    ngOnChanges() {
        const siLink = this.siLink();
        if (!siLink) {
            this.href.set(undefined);
            return;
        }
        this.destroyer.next();
        if (siLink.tooltip) {
            this.translateService
                .translateAsync(siLink.tooltip)
                .pipe(takeUntil(this.destroyer))
                .subscribe(text => this.title.set(text));
        }
        if (siLink.action) {
            this.href.set('');
        }
        else if (siLink.link) {
            this.subscribeRouter();
        }
        else if (siLink.href) {
            this.href.set(siLink.href);
            this.target.set(siLink.target ?? this.siLinkDefaultTarget());
        }
        else {
            // In case the siLink has no link, href or action,
            // we remove the href to avoid the mouse pointer.
            this.href.set(undefined);
        }
    }
    ngDoCheck() {
        // this deep-checks if isActive has changed. It then updates the internal state and emits the event
        // to be symmetric with the router-link case. queueMicroTask avoids "Expression has changed after it was checked" errors
        const siLink = this.siLink();
        if (siLink &&
            !siLink.link &&
            siLink.isActive !== undefined &&
            this.active() !== siLink.isActive) {
            this.active.set(siLink.isActive);
            queueMicrotask(() => {
                this.activeChange.emit(this.active());
            });
        }
    }
    subscribeRouter() {
        if (!this.router || !this.activatedRoute) {
            return;
        }
        // Initial check
        this.updateActiveByRouter();
        this.router.events
            .pipe(takeUntil(this.destroyer), filter(e => e instanceof NavigationEnd))
            .subscribe(() => this.updateActiveByRouter());
    }
    updateActiveByRouter() {
        const urlTree = this.urlTree;
        this.active.set(this.siLink().isActive ??
            this.router.isActive(urlTree, this.exactMatch()
                ? {
                    queryParams: 'exact',
                    matrixParams: 'exact',
                    paths: 'exact',
                    fragment: 'exact'
                }
                : {
                    paths: 'subset',
                    queryParams: 'subset',
                    fragment: 'ignored',
                    matrixParams: 'ignored'
                }));
        this.href.set(this.locationStrategy.prepareExternalUrl(this.router.serializeUrl(urlTree)));
    }
    onClick(event) {
        const siLink = this.siLink();
        if (siLink?.action) {
            event.preventDefault();
            const actionParam = this.actionParam();
            if (typeof siLink.action === 'string') {
                this.actionService?.emit(siLink, this.actionParam());
            }
            else if (actionParam === undefined) {
                siLink.action();
            }
            else {
                siLink.action(actionParam);
            }
            return;
        }
        // ignore regular links, allow user to open links in new tab or window
        if (!siLink ||
            siLink.href ||
            event.button > 0 ||
            event.ctrlKey ||
            event.metaKey ||
            event.shiftKey) {
            return;
        }
        event.preventDefault();
        // We have links without any action, href or link. For example grouping navbar items that hold a
        // dropdown with links. That is why we need to check if the link property is set.
        if (siLink.link && this.router) {
            this.router.navigateByUrl(this.urlTree, this.navigationExtras);
        }
    }
    static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.0.8", ngImport: i0, type: SiLinkDirective, deps: [], target: i0.ɵɵFactoryTarget.Directive });
    static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "17.1.0", version: "21.0.8", type: SiLinkDirective, isStandalone: true, selector: "[siLink]", inputs: { siLink: { classPropertyName: "siLink", publicName: "siLink", isSignal: true, isRequired: false, transformFunction: null }, siLinkDefaultTarget: { classPropertyName: "siLinkDefaultTarget", publicName: "siLinkDefaultTarget", isSignal: true, isRequired: false, transformFunction: null }, actionParam: { classPropertyName: "actionParam", publicName: "actionParam", isSignal: true, isRequired: false, transformFunction: null }, activeClass: { classPropertyName: "activeClass", publicName: "activeClass", isSignal: true, isRequired: false, transformFunction: null }, exactMatch: { classPropertyName: "exactMatch", publicName: "exactMatch", isSignal: true, isRequired: false, transformFunction: null }, ariaCurrent: { classPropertyName: "ariaCurrent", publicName: "ariaCurrent", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { activeChange: "activeChange" }, host: { listeners: { "click": "onClick($event)" }, properties: { "attr.href": "href()", "attr.target": "target()", "attr.title": "title()", "attr.aria-current": "isAriaCurrent()", "class": "active() ? activeClass() : null" } }, exportAs: ["siLink"], usesOnChanges: true, ngImport: i0 });
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.8", ngImport: i0, type: SiLinkDirective, decorators: [{
            type: Directive,
            args: [{
                    selector: '[siLink]',
                    host: {
                        '[attr.href]': 'href()',
                        '[attr.target]': 'target()',
                        '[attr.title]': 'title()',
                        '[attr.aria-current]': 'isAriaCurrent()',
                        '[class]': 'active() ? activeClass() : null'
                    },
                    exportAs: 'siLink'
                }]
        }], propDecorators: { siLink: [{ type: i0.Input, args: [{ isSignal: true, alias: "siLink", required: false }] }], siLinkDefaultTarget: [{ type: i0.Input, args: [{ isSignal: true, alias: "siLinkDefaultTarget", required: false }] }], actionParam: [{ type: i0.Input, args: [{ isSignal: true, alias: "actionParam", required: false }] }], activeClass: [{ type: i0.Input, args: [{ isSignal: true, alias: "activeClass", required: false }] }], exactMatch: [{ type: i0.Input, args: [{ isSignal: true, alias: "exactMatch", required: false }] }], ariaCurrent: [{ type: i0.Input, args: [{ isSignal: true, alias: "ariaCurrent", required: false }] }], activeChange: [{ type: i0.Output, args: ["activeChange"] }], onClick: [{
                type: HostListener,
                args: ['click', ['$event']]
            }] } });

/**
 * Copyright (c) Siemens 2016 - 2026
 * SPDX-License-Identifier: MIT
 */
class SiLinkModule {
    static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.0.8", ngImport: i0, type: SiLinkModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule });
    static ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "14.0.0", version: "21.0.8", ngImport: i0, type: SiLinkModule, imports: [SiLinkDirective], exports: [SiLinkDirective] });
    static ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "21.0.8", ngImport: i0, type: SiLinkModule });
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.8", ngImport: i0, type: SiLinkModule, decorators: [{
            type: NgModule,
            args: [{
                    imports: [SiLinkDirective],
                    exports: [SiLinkDirective]
                }]
        }] });

/**
 * Copyright (c) Siemens 2016 - 2026
 * SPDX-License-Identifier: MIT
 */

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

export { SI_LINK_DEFAULT_NAVIGATION_EXTRA, SiLinkActionService, SiLinkDirective, SiLinkModule };
//# sourceMappingURL=siemens-element-ng-link.mjs.map
