import { AXPSettingDefinitionProviderService, AXPSettingService, AXP_SEARCH_PROVIDER, AXP_SEARCH_DEFINITION_PROVIDER, AXP_MENU_PROVIDER } from '@acorex/platform/common';
import { AXPPageStatus } from '@acorex/platform/layout/widget-core';
import * as i0 from '@angular/core';
import { computed, inject, NgModule } from '@angular/core';
import { signalStore, withState, withComputed, withMethods, patchState, withHooks } from '@ngrx/signals';
import { get, isEqual, isNil, isEmpty, sortBy } from 'lodash-es';
import { filter, merge, firstValueFrom } from 'rxjs';
import { AXToastService } from '@acorex/components/toast';
import { AXTranslationService } from '@acorex/core/translation';
import * as i1 from '@acorex/platform/core';
import { resolvePlatformScopeName, AXPPlatformScope } from '@acorex/platform/core';
import { AXLocaleService } from '@acorex/core/locale';
import { AXPLayoutThemeService } from '@acorex/platform/themes/shared';
import { AXPSessionService, AXPAuthGuard } from '@acorex/platform/auth';
import { AXPRootLayoutComponent } from '@acorex/platform/themes/default';
import { ROUTES } from '@angular/router';

function searchSettings(groups, search) {
    const sectionMatchResult = [];
    const settingMatchResult = [];
    const processedGroups = new Set();
    const createGroupIdentifier = (group) => `${group.name}-${group.title}`;
    const addGroupToResult = (group, sections, resultArray) => {
        const groupId = createGroupIdentifier(group);
        if (!processedGroups.has(groupId)) {
            resultArray.push({
                ...group,
                sections,
                groups: [], // Exclude nested groups
            });
            processedGroups.add(groupId);
        }
    };
    const processSections = (group, filterFn) => {
        const matchedSections = group.sections.filter(filterFn);
        if (matchedSections.length > 0) {
            addGroupToResult(group, matchedSections, sectionMatchResult);
        }
    };
    const processSettings = (group, filterFn) => {
        const matchedSections = group.sections
            .map(filterFn)
            .filter((section) => section !== null);
        if (matchedSections.length > 0) {
            addGroupToResult(group, matchedSections, settingMatchResult);
        }
    };
    const sectionMatches = (section) => section.name.toLowerCase().includes(search.toLowerCase()) ||
        section.title.toLowerCase().includes(search.toLowerCase());
    const filterSettings = (section) => {
        const matchedSettings = section.settings.filter((setting) => setting.name.toLowerCase().includes(search.toLowerCase()) ||
            setting.title.toLowerCase().includes(search.toLowerCase()));
        return matchedSettings.length > 0 ? { ...section, settings: matchedSettings } : null;
    };
    const processGroupRecursively = (group) => {
        processSections(group, sectionMatches); // Match sections with all settings
        processSettings(group, filterSettings); // Match settings within sections
        group.groups.forEach(processGroupRecursively); // Recurse into nested groups
    };
    groups.forEach(processGroupRecursively);
    return [...sectionMatchResult, ...settingMatchResult];
}

const AXPSettingsViewModel = signalStore(withState(() => ({
    groups: [],
    activateGroup: undefined,
    scope: 'U',
    //
    searchExpression: null,
    //
    previousContext: {},
    context: {},
    //
    status: AXPPageStatus.Processing,
    form: null,
})), withComputed((store, layout = inject(AXPLayoutThemeService)) => ({
    searchResults: computed(() => searchSettings(store.groups(), store.searchExpression())),
    hasActivateGroup: computed(() => store.activateGroup() != null),
    showGroups: computed(() => store.activateGroup() != null && layout.isLarge()),
    scopeTitle: computed(() => {
        return `${resolvePlatformScopeName(store.scope())}.title`;
    }),
    scopeDescription: computed(() => {
        return `${resolvePlatformScopeName(store.scope())}.description`;
    }),
    isSearching: computed(() => store.searchExpression() != null),
    isBusy: computed(() => store.status() == AXPPageStatus.Processing),
    isSaving: computed(() => store.status() == AXPPageStatus.Submitting),
    isLoaded: computed(() => store.groups().length > 0),
})), withMethods((store, settingDefinitionService = inject(AXPSettingDefinitionProviderService), settingValueService = inject(AXPSettingService), toastService = inject(AXToastService), translateService = inject(AXTranslationService)) => ({
    registerForm(form) {
        patchState(store, {
            form: form,
        });
    },
    async load(scope) {
        patchState(store, {
            scope: scope,
            status: AXPPageStatus.Processing,
        });
        //
        const groups = await settingDefinitionService.getListAsync(scope);
        patchState(store, {
            groups: groups,
        });
        const currentContext = await settingValueService.scope(scope).all();
        const defaults = await settingValueService.scope(scope).defaultValues();
        patchState(store, {
            context: { ...defaults, ...currentContext },
        });
        patchState(store, {
            previousContext: store.context(),
            status: AXPPageStatus.Rendered,
        });
    },
    async reload() {
        await settingDefinitionService.reload();
        const groups = await settingDefinitionService.getListAsync(store.scope());
        const oldActivateGroupName = store.activateGroup()?.name;
        patchState(store, {
            groups: groups,
            activateGroup: undefined,
        });
        if (oldActivateGroupName) {
            this.setActivateGroupByName(oldActivateGroupName);
        }
    },
    updateContext(context) {
        patchState(store, {
            context: { ...store.context(), ...context },
        });
    },
    updatePreviousContext(context) {
        patchState(store, {
            previousContext: { ...store.previousContext(), ...context },
        });
    },
    setActivateGroup(group) {
        patchState(store, {
            activateGroup: group,
        });
    },
    unloadActivateGroup() {
        patchState(store, {
            activateGroup: undefined,
        });
    },
    setActivateGroupByName(name) {
        const group = store.groups().find(g => g.name === name);
        if (group) {
            patchState(store, {
                activateGroup: group,
            });
        }
    },
    //
    async search(expression) {
        if (!isNil(expression) && !isEmpty(expression)) {
            patchState(store, {
                searchExpression: expression,
            });
        }
        else {
            patchState(store, {
                searchExpression: null,
            });
        }
    },
    clearSearch() {
        patchState(store, {
            searchExpression: null,
        });
    },
    isDirty() {
        return store.groups()?.some((group) => group.sections.some((sec) => sec.settings.some((setting) => {
            const currentValue = get(store.context(), setting.name);
            const previousValue = get(store.previousContext(), setting.name);
            return !isEqual(currentValue, previousValue);
        }))) || false;
    },
    async apply() {
        const i18nScope = "settings";
        try {
            if (await store.form() && this.isDirty()) {
                const form = store.form();
                form.resetErrors();
                //
                patchState(store, {
                    status: AXPPageStatus.Submitting,
                });
                const formResult = await form.validate();
                if (!formResult.result) {
                    toastService.show({
                        color: 'danger',
                        title: await translateService.translateAsync('@general:actions.apply.messages.invalid.title'),
                        content: await translateService.translateAsync('@general:actions.apply.messages.invalid.message'),
                        location: 'bottom-center',
                        closeButton: true,
                        timeOut: 3000,
                        timeOutProgress: true,
                    });
                    patchState(store, {
                        status: AXPPageStatus.Error,
                    });
                    return false;
                }
                await settingValueService.scope(store.scope()).set(store.context());
                // Show success notification
                toastService.show({
                    color: 'success',
                    title: await translateService.translateAsync('@general:actions.apply.success.title'),
                    content: await translateService.translateAsync('@general:actions.apply.success.message'),
                    location: 'bottom-center',
                    closeButton: true,
                    timeOut: 3000,
                    timeOutProgress: true,
                });
                patchState(store, {
                    status: AXPPageStatus.Submitted,
                });
                return true;
            }
            return false;
        }
        catch (error) {
            toastService.show({
                color: 'danger',
                title: await translateService.translateAsync('@general:actions.apply.error.title'),
                content: await translateService.translateAsync('@general:actions.apply.error.message'),
                location: 'bottom-center',
                closeButton: true,
                timeOut: 3000,
                timeOutProgress: true,
            });
            patchState(store, {
                status: AXPPageStatus.Error,
            });
            return false;
        }
    },
    async discard() {
        const form = store.form();
        form.resetErrors();
        //
        patchState(store, {
            status: AXPPageStatus.Rendered,
        });
        patchState(store, {
            context: store.previousContext(),
        });
    },
    async resetToDefault() {
        // Update the context  with the defaults
        const defaults = await settingValueService.scope(store.scope()).defaultValues();
        patchState(store, {
            context: defaults,
        });
        //
        const result = await this.apply();
        if (!result) {
            this.discard();
        }
    },
})), withHooks((store, settingValueService = inject(AXPSettingService), translationService = inject(AXTranslationService), localeService = inject(AXLocaleService)) => ({
    async onInit() {
        //
        settingValueService.onChanged.pipe(filter((c) => c.scope == store.scope())).subscribe((e) => {
            e.keys.forEach((k) => {
                const currentValue = e.values[k];
                const contextValue = get(store.context(), k);
                const previousValue = get(store.previousContext(), k);
                // Update only if there are actual changes
                if (!isEqual(previousValue, currentValue) || !isEqual(currentValue, contextValue)) {
                    patchState(store, {
                        previousContext: {
                            ...store.previousContext(),
                            [k]: currentValue,
                        }
                    });
                    patchState(store, {
                        context: {
                            ...store.context(),
                            [k]: currentValue,
                        }
                    });
                }
            });
        });
        //
        merge(translationService.langChanges$, localeService.profileChanged$).subscribe(async () => {
            if (store.isLoaded()) {
                await store.reload();
            }
        });
    },
    onDestroy() { },
})));

class AXPSettingSearchDefinitionProvider {
    async provide(context) {
        context.addDefinition('setting', 'Setting', 'setting', 'fa-solid fa-gear', 3, {
            format: {
                id: '{{data.name}}',
            },
            actions: [
                {
                    name: 'navigate',
                    type: 'view',
                    priority: 'primary',
                },
            ],
        });
    }
}

class AXPSettingSearchProvider {
    constructor() {
        this.settingService = inject(AXPSettingDefinitionProviderService);
        this.sessionService = inject(AXPSessionService);
    }
    async search(text) {
        const groupsSetting = this.settingService.getList(AXPPlatformScope.User);
        if (groupsSetting.length == 0) {
            groupsSetting.push(...(await this.settingService.getListAsync(AXPPlatformScope.User)));
        }
        // Step 2: Flatten settings from groups
        const allSettings = [];
        const extractSettings = (group) => {
            for (const section of group.sections) {
                allSettings.push(...section.settings.map((x) => ({ ...x, group })));
            }
            for (const subGroup of group.groups) {
                extractSettings(subGroup); // Recursive extraction
            }
        };
        for (const group of groupsSetting) {
            extractSettings(group);
        }
        // Step 3: Search settings by title
        const searchResults = allSettings.filter((setting) => setting.title.toLowerCase().includes(text.toLowerCase()));
        return sortBy(searchResults.map((setting) => ({
            title: setting.title,
            description: setting.description,
            group: 'setting',
            data: setting,
            command: {
                name: 'navigate',
                options: {
                    type: 'router',
                    options: {
                        path: `/${this.sessionService.application?.name}/settings/user/${setting.group.name}#${setting.title}`,
                    },
                }
            },
            parent: setting.group
                ? {
                    title: setting.group.title,
                    data: setting.group,
                }
                : undefined,
        })), ['title']);
    }
}

const AXPSettingsManagementMenuKeys = {
    UserSettings: 'settings:user:profile',
    TenantApplicationSettings: 'settings:tenant:application',
};

class AXMMenuProvider {
    constructor() {
        this.sessionService = inject(AXPSessionService);
    }
    async provide(context) {
        const appName = this.sessionService.application?.name;
        const isAuthorized = await firstValueFrom(this.sessionService.isAuthorized$);
        if (!isAuthorized) {
            return;
        }
        context.find('user:profile').addItems([
            {
                name: AXPSettingsManagementMenuKeys.UserSettings,
                text: '@settings:user.title',
                icon: 'fa-light fa-gear',
                path: `/${this.sessionService.application?.name}/settings/user`,
            },
        ]);
        context.addItems([
            {
                name: AXPSettingsManagementMenuKeys.TenantApplicationSettings,
                priority: 10000000,
                text: '@settings:tenant.title',
                type: 'menu',
                icon: 'fa-light fa-gear',
                path: `/${appName}/settings/tenant`,
                data: {
                    requiredPermission: 'admin',
                },
            },
        ]);
    }
}

function routesFacory() {
    let routes = [
        {
            path: ':app/settings/:scope',
            canActivate: [AXPAuthGuard],
            loadComponent: () => {
                return AXPRootLayoutComponent;
            },
            children: [
                {
                    path: '',
                    loadComponent: () => import('./acorex-modules-settings-management-setting-page.component-7k6J8wut.mjs').then((c) => c.AXPSettingPageComponent),
                    data: { reuse: true },
                    children: [
                        {
                            path: ':group',
                            loadComponent: () => import('./acorex-modules-settings-management-setting-view.component-Cpny-0pe.mjs').then((c) => c.AXPSettingsViewComponent),
                        },
                    ],
                },
            ],
        },
    ];
    return routes;
}
class AXMSettingsManagementModule {
    constructor(appInitService, injector) { }
    static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.4", ngImport: i0, type: AXMSettingsManagementModule, deps: [{ token: i1.AXPAppStartUpService }, { token: i0.Injector }], target: i0.ɵɵFactoryTarget.NgModule }); }
    static { this.ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "14.0.0", version: "20.3.4", ngImport: i0, type: AXMSettingsManagementModule }); }
    static { this.ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "20.3.4", ngImport: i0, type: AXMSettingsManagementModule, providers: [
            {
                provide: AXP_SEARCH_PROVIDER,
                useClass: AXPSettingSearchProvider,
                multi: true,
            },
            {
                provide: AXP_SEARCH_DEFINITION_PROVIDER,
                useClass: AXPSettingSearchDefinitionProvider,
                multi: true,
            },
            {
                provide: ROUTES,
                multi: true,
                useFactory: routesFacory,
            },
            {
                provide: AXP_MENU_PROVIDER,
                useClass: AXMMenuProvider,
                multi: true,
            },
        ] }); }
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.4", ngImport: i0, type: AXMSettingsManagementModule, decorators: [{
            type: NgModule,
            args: [{
                    imports: [],
                    exports: [],
                    declarations: [],
                    providers: [
                        {
                            provide: AXP_SEARCH_PROVIDER,
                            useClass: AXPSettingSearchProvider,
                            multi: true,
                        },
                        {
                            provide: AXP_SEARCH_DEFINITION_PROVIDER,
                            useClass: AXPSettingSearchDefinitionProvider,
                            multi: true,
                        },
                        {
                            provide: ROUTES,
                            multi: true,
                            useFactory: routesFacory,
                        },
                        {
                            provide: AXP_MENU_PROVIDER,
                            useClass: AXMMenuProvider,
                            multi: true,
                        },
                    ],
                }]
        }], ctorParameters: () => [{ type: i1.AXPAppStartUpService }, { type: i0.Injector }] });

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

export { AXMSettingsManagementModule, AXPSettingsViewModel };
//# sourceMappingURL=acorex-modules-settings-management.mjs.map
