import { AXP_ROOT_CONFIG_TOKEN, AXPFilterOperatorMiddlewareService, AXPFileStorageService, AXPFileStorageStatus } from '@acorex/platform/common';
import * as i1 from '@angular/common/http';
import { HttpParams, HttpClient, HttpHeaders } from '@angular/common/http';
import * as i0 from '@angular/core';
import { inject, Injectable, NgModule } from '@angular/core';
import { kebabCase } from 'lodash-es';
import { firstValueFrom, catchError, of, BehaviorSubject, tap, filter, take, switchMap } from 'rxjs';
import * as i2 from '@acorex/platform/auth';
import { AXPAuthStrategy, AXPSessionService, JwtUtil, TimeUtil, PkceUtil, AXPAuthModule, AXP_TENANT_LOADER, AXP_APPLICATION_LOADER, AXP_PERMISSION_LOADER, AXP_FEATURE_LOADER } from '@acorex/platform/auth';
import { AXPEntityStorageService } from '@acorex/platform/layout/entity';
import { AXP_USER_AVATAR_PROVIDER } from '@acorex/platform/layout/components';
import { STRATEGY_CONFIG_TOKEN } from '@acorex/platform/layout/widgets';
import * as i1$1 from 'angular-oauth2-oidc';
import { OAuthService, OAuthModule } from 'angular-oauth2-oidc';
import { AXM_AUTH_CONFIG_TOKEN } from '@acorex/modules/auth';
import { Router } from '@angular/router';
import { AXMUsersEntityService } from '@acorex/modules/security-management';
import { AXPDataGenerator } from '@acorex/platform/core';
import { AXCUtilsModule, AXCExternalAuthorizationService } from '@acorex/connectivity/utils';
import { AXPRuntimeModule, provideCommandSetups } from '@acorex/platform/runtime';
import { AXPReportViewerService } from '@acorex/modules/report-management';

class AXCApiEntityStorageService {
    constructor(http) {
        this.http = http;
        this.configs = inject(AXP_ROOT_CONFIG_TOKEN);
        this.filterService = inject(AXPFilterOperatorMiddlewareService);
        this.mainUrl = this.configs.baseUrl;
        // API routing constants
        this.API_VERSION = 'v1';
        this.DEFAULT_AREA = 'global';
    }
    get dbName() {
        return 'ACoreXPlatform';
    }
    getConfigEntity(entityName) {
        const partEntity = entityName.split('.');
        if (partEntity.length == 3) {
            const [area, module, entity] = partEntity;
            const areaKebab = kebabCase(area);
            const moduleKebab = kebabCase(module);
            const entityKebab = kebabCase(entity);
            return {
                module: moduleKebab,
                entity: entityKebab,
                area: areaKebab,
                version: this.API_VERSION,
            };
        }
        else {
            const [module, entity] = partEntity;
            const moduleKebab = kebabCase(module);
            const entityKebab = kebabCase(entity);
            return {
                module: moduleKebab,
                entity: entityKebab,
                area: this.DEFAULT_AREA,
                version: this.API_VERSION,
            };
        }
    }
    async initial(entityName, collection) {
        //const exists = await this.table('entity-store').where({ entityName }).count();
        // if (exists === 0) {
        //   await this.table('entity-store').bulkAdd(collection.map((item) => ({ ...item, entityName })));
        // }
        return collection;
    }
    async getOne(entityName, id) {
        const routeElement = await this.getConfigEntity(entityName);
        const url = `${this.mainUrl}/${routeElement.version}/${routeElement.area}/${routeElement.module}/${routeElement.entity}${id ? '/' + id : ''}`;
        return firstValueFrom(this.http.get(url));
    }
    async updateOne(entityName, id, keyValue) {
        const routeElement = await this.getConfigEntity(entityName);
        const url = `${this.mainUrl}/${routeElement.version}/${routeElement.area}/${routeElement.module}/${routeElement.entity}${id ? '/' + id : ''}`;
        return firstValueFrom(this.http.put(url, keyValue));
    }
    async deleteOne(entityName, id) {
        const routeElement = await this.getConfigEntity(entityName);
        const url = `${this.mainUrl}/${routeElement.version}/${routeElement.area}/${routeElement.module}/${routeElement.entity}/${id}`;
        firstValueFrom(this.http.delete(url));
    }
    async insertOne(entityName, entityItem) {
        const routeElement = await this.getConfigEntity(entityName);
        const url = `${this.mainUrl}/${routeElement.version}/${routeElement.area}/${routeElement.module}/${routeElement.entity}`;
        return firstValueFrom(this.http.post(url, entityItem));
    }
    async getAll(entityName) {
        return [];
    }
    async query(entityName, request) {
        const routeElement = await this.getConfigEntity(entityName);
        let httpParams = new HttpParams().set('Skip', request.skip).set('Take', request.take);
        if (request?.sort && request?.sort.length > 0) {
            const sortParam = request?.sort.map((sort) => `${sort.field}:${sort.dir}`).join(',');
            httpParams = httpParams.set('$orderby', sortParam);
        }
        const greaterThanOperator = this.filterService.getOperator('greaterThan');
        const lessThanOperator = this.filterService.getOperator('lessThan');
        function generateQueryString(filter) {
            if (!filter.filters) {
                // Base case: single filter
                if (typeof filter.value === 'object' && filter.operator.type === 'between') {
                    return `${filter.field} ${greaterThanOperator.type} '${filter.value.from}' and ${filter.field} ${lessThanOperator.type} '${filter.value.to}'`;
                }
                else {
                    return `${filter.field} ${filter.operator.type} '${filter.value}'`;
                }
            }
            else if (!filter.filters.length) {
                return;
            }
            else {
                // Recursive case: multiple filters
                const filterStrings = filter.filters.map((subFilter) => generateQueryString(subFilter));
                const logic = filter.logic || 'AND'; // Default logic is 'AND' if not provided
                return `${filterStrings.filter((i) => i).join(` ${logic} `)}`;
            }
        }
        let queryString = '';
        if (request.filter) {
            const filter = request.filter;
            if (filter.filters && filter.filters.length > 0) {
                // Construct filter string from provided filters
                const dynamicQueries = generateQueryString(filter);
                console.log({ dynamicQueries: dynamicQueries });
                // Append dynamic filters to custom filter, if both exist
                queryString = (queryString ? `${queryString},${dynamicQueries}` : dynamicQueries);
            }
        }
        // Set the $filter parameter if there are any filters
        if (queryString) {
            httpParams = httpParams.set('$query', queryString);
        }
        return firstValueFrom(this.http.get(`${this.mainUrl}/${routeElement.version}/${routeElement.area}/${routeElement.module}/${routeElement.entity}`, { params: httpParams })).then((response) => {
            return {
                total: response.totalCount,
                items: response.items,
            };
        });
    }
    static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: AXCApiEntityStorageService, deps: [{ token: i1.HttpClient }], target: i0.ɵɵFactoryTarget.Injectable }); }
    static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: AXCApiEntityStorageService }); }
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: AXCApiEntityStorageService, decorators: [{
            type: Injectable
        }], ctorParameters: () => [{ type: i1.HttpClient }] });

class AXCFileStorageApiService extends AXPFileStorageService {
    constructor() {
        super(...arguments);
        this.http = inject(HttpClient);
        //#region ----   API Endpoints   ----
        this.baseUrl = '/api/file-storage';
        //#endregion
        //#region ----   Fallback Data   ----
        this.fallbackFileInfo = {
            fileId: 'fallback-file-id',
            refId: 'fallback-ref-id',
            refType: 'fallback-ref-type',
            category: 'fallback-category',
            size: 0,
            mimeType: 'application/octet-stream',
            uploadedAt: new Date(),
            isPublic: true,
            isPrimary: false,
            status: AXPFileStorageStatus.Temporary,
            name: 'fallback-file',
            binary: new File([''], 'fallback-file'),
        };
    }
    //#endregion
    async save(request) {
        try {
            const formData = new FormData();
            formData.append('file', request.file);
            formData.append('refId', request.refId);
            formData.append('refType', request.refType);
            formData.append('category', request.category);
            if (request.name) {
                formData.append('name', request.name);
            }
            if (request.path) {
                formData.append('path', request.path);
            }
            if (request.isPrimary !== undefined) {
                formData.append('isPrimary', request.isPrimary.toString());
            }
            if (request.status) {
                formData.append('status', request.status);
            }
            if (request.metadata) {
                formData.append('metadata', JSON.stringify(request.metadata));
            }
            return await firstValueFrom(this.http.post(`${this.baseUrl}/save`, formData).pipe(catchError(() => of(this.fallbackFileInfo))));
        }
        catch {
            return this.fallbackFileInfo;
        }
    }
    async update(request) {
        try {
            const updateData = {
                metadata: request.metadata,
            };
            if (request.path !== undefined) {
                updateData.path = request.path;
            }
            if (request.name !== undefined) {
                updateData.name = request.name;
            }
            if (request.isPrimary !== undefined) {
                updateData.isPrimary = request.isPrimary;
            }
            return await firstValueFrom(this.http.put(`${this.baseUrl}/update/${request.fileId}`, updateData).pipe(catchError(() => of(this.fallbackFileInfo))));
        }
        catch {
            return this.fallbackFileInfo;
        }
    }
    async find(request) {
        try {
            let params = new HttpParams();
            if (request.refId) {
                params = params.set('refId', request.refId);
            }
            if (request.refType) {
                params = params.set('refType', request.refType);
            }
            if (request.category) {
                params = params.set('category', request.category);
            }
            if (request.mimeType) {
                params = params.set('mimeType', request.mimeType);
            }
            if (request.isPublic !== undefined) {
                params = params.set('isPublic', request.isPublic.toString());
            }
            if (request.isPrimary !== undefined) {
                params = params.set('isPrimary', request.isPrimary.toString());
            }
            if (request.uploadedAtRange) {
                params = params.set('uploadedAtFrom', request.uploadedAtRange.from.toISOString());
                params = params.set('uploadedAtTo', request.uploadedAtRange.to.toISOString());
            }
            return await firstValueFrom(this.http.get(`${this.baseUrl}/find`, { params }).pipe(catchError(() => of([]))));
        }
        catch {
            return [];
        }
    }
    async getInfo(fileId) {
        try {
            return await firstValueFrom(this.http.get(`${this.baseUrl}/info/${fileId}`).pipe(catchError(() => of(this.fallbackFileInfo))));
        }
        catch {
            return this.fallbackFileInfo;
        }
    }
    async findMany(ids) {
        try {
            return await firstValueFrom(this.http.post(`${this.baseUrl}/find-many`, { ids }).pipe(catchError(() => of([]))));
        }
        catch {
            return [];
        }
    }
    async remove(fileId) {
        try {
            await firstValueFrom(this.http.delete(`${this.baseUrl}/remove/${fileId}`).pipe(catchError(() => of(void 0))));
        }
        catch {
            // Silently fail in fallback mode
        }
    }
    async commit(fileId) {
        try {
            await firstValueFrom(this.http.post(`${this.baseUrl}/commit/${fileId}`, {}).pipe(catchError(() => of(void 0))));
        }
        catch {
            // Silently fail in fallback mode
        }
    }
    async markForDeletion(fileId) {
        try {
            await firstValueFrom(this.http.post(`${this.baseUrl}/mark-for-deletion/${fileId}`, {}).pipe(catchError(() => of(void 0))));
        }
        catch {
            // Silently fail in fallback mode
        }
    }
    static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: AXCFileStorageApiService, deps: null, target: i0.ɵɵFactoryTarget.Injectable }); }
    static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: AXCFileStorageApiService }); }
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: AXCFileStorageApiService, decorators: [{
            type: Injectable
        }] });

class AXMOidcApplicationLoader {
    constructor(http) {
        this.http = http;
        this.configs = inject(AXP_ROOT_CONFIG_TOKEN);
        this.apiGetApps = `${this.configs.baseUrl}/applications/applications-for-current-tenant`;
        this.apiSetApp = `${this.configs.baseUrl}/SetApplication`;
    }
    async getList(context) {
        const response = await firstValueFrom(this.http.get(this.apiGetApps));
        return response.items.map((item) => this.mapToAXPApplication(item));
    }
    set(application) {
        return Promise.resolve();
    }
    // //TODO: shoud be removed
    // set(application: AXPApplication): Observable<AXPRefreshTokenResult> {
    //   return this.http.post<any>(this.apiSetApp, { applicationId: application.id }).pipe(
    //     map((response) => {
    //       return {
    //         succeed: true,
    //         data: {
    //           accessToken: response.token,
    //           refreshToken: response.token,
    //         }
    //       };
    //     })
    //   );
    // }
    mapToAXPApplication(item) {
        return {
            id: item.id,
            name: item.name || 'defaultName',
            title: item.title || 'defaultTitle',
            version: item.version || '1.0.0',
            description: item.description,
            logo: item.logo, // Assuming logo is of type AXPLogoConfig or undefined
            edition: item.edition
                ? {
                    id: item.edition.id,
                    title: item.edition.title,
                    description: item.edition.description,
                }
                : undefined,
            // features: item.features || [],
        };
    }
    static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: AXMOidcApplicationLoader, deps: [{ token: i1.HttpClient }], target: i0.ɵɵFactoryTarget.Injectable }); }
    static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: AXMOidcApplicationLoader }); }
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: AXMOidcApplicationLoader, decorators: [{
            type: Injectable
        }], ctorParameters: () => [{ type: i1.HttpClient }] });

class AXMConfigurationService {
    constructor(http) {
        this.http = http;
        this.configs = inject(AXP_ROOT_CONFIG_TOKEN);
        this.applicationConfig = null;
        this.apiGetConfig = `${this.configs.baseUrl}/abp/application-configuration`;
        this.fetchInProgress = false;
        this.configSubject = new BehaviorSubject(null);
        this.init().subscribe(); // Automatically trigger configuration load on service instantiation
    }
    init() {
        if (!this.fetchInProgress) {
            this.fetchInProgress = true;
            return this.http.get(this.apiGetConfig).pipe(tap((response) => {
                this.applicationConfig = response;
                this.configSubject.next(this.applicationConfig);
                this.fetchInProgress = false;
            }));
        }
        else {
            // Adjusted approach to handle TypeScript's type safety requirements
            return this.configSubject.asObservable().pipe(filter((config) => config !== null), take(1) // Ensures it completes after emitting the first non-null value
            );
        }
    }
    getConfig() {
        if (this.applicationConfig) {
            // If the config is already loaded, return it immediately
            return of(this.applicationConfig);
        }
        else {
            // If the config is not loaded, initiate loading
            return this.configSubject.asObservable().pipe(filter((config) => config !== null), take(1), // Ensure it only emits the first non-null value and completes
            switchMap(() => of(this.applicationConfig)));
        }
    }
    static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: AXMConfigurationService, deps: [{ token: i1.HttpClient }], target: i0.ɵɵFactoryTarget.Injectable }); }
    static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: AXMConfigurationService, providedIn: 'root' }); }
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: AXMConfigurationService, decorators: [{
            type: Injectable,
            args: [{
                    providedIn: 'root',
                }]
        }], ctorParameters: () => [{ type: i1.HttpClient }] });

class AXMOidcFeatureLoader {
    constructor() {
        this.list = [
            {
                name: 'axp-entity-list-custom-view',
                title: 'Custom View',
                value: false
            },
            {
                name: 'axp-entity-list-quick-search',
                title: 'Custom View',
                value: false
            }
        ];
    }
    async getList(context) {
        return this.list;
    }
}

//#endregion
class AXCAPIOidcStrategy extends AXPAuthStrategy {
    constructor() {
        super(...arguments);
        this.aXMAuthConfigs = inject(AXM_AUTH_CONFIG_TOKEN);
        this.oauthService = inject(OAuthService);
        this.http = inject(HttpClient);
        this.sessionService = inject(AXPSessionService);
        this.router = inject(Router);
    }
    async configureOAuth() {
        if (this.openidConfigurationInfo)
            return;
        // Validation: اطمینان از وجود authConfig
        if (!this.aXMAuthConfigs.authConfig) {
            throw new Error('authConfig is missing. Please check your environment configuration.');
        }
        this.oauthService.configure(this.aXMAuthConfigs.authConfig);
        this.oauthService.setStorage(localStorage);
        this.openidConfigurationInfo = await this.oauthService.loadDiscoveryDocument();
        if (!this.openidConfigurationInfo) {
            throw new Error('openidConfigurationInfo is missing');
        }
        this.oauthService.events.subscribe(async (event) => {
            // console.log('event', event);
            // if (event.type === 'token_received') {
            //   console.log('Token has been refreshed');
            // }
            // if (event.type === 'token_expires') {
            //   console.log('Token is about to expire. Triggering silent refresh...');
            // }
        });
        const oidcJson = localStorage.getItem(AXPSessionService.SESSION_KEY);
        if (oidcJson) {
            const authData = JSON.parse(oidcJson);
            if (authData) {
                this.sessionService.setSession(authData);
                if (authData.expiresIn && new Date(authData.expiresIn) < new Date()) {
                    if (authData.expiresIn) {
                        this.sessionService.refreshToken();
                    }
                    else {
                        this.signout();
                    }
                }
            }
        }
    }
    async signin(credentials) {
        // If OIDC with username/password
        if (credentials.strategy === 'oidc' && credentials.username && credentials.password) {
            await this.handleOidcPasswordSignin(credentials);
            await new Promise(() => { }); // Keeps the promise pending until another flow (e.g., OAuth callback) completes
        }
        throw new Error(`Authentication method or credentials not supported: ${credentials.strategy}`);
    }
    async handleOidcPasswordSignin(credentials) {
        await this.configureOAuth();
        // Validation: اطمینان از وجود baseUrl
        if (!this.aXMAuthConfigs.baseUrl) {
            throw new Error('baseUrl is missing. Please check your environment configuration.');
        }
        // استفاده از baseUrl از configuration
        const baseUrl = this.aXMAuthConfigs.baseUrl;
        const loginRes = await fetch(baseUrl + '/auth/manual-login', {
            method: 'POST',
            headers: { 'Content-Type': 'application/json' },
            body: JSON.stringify({ username: credentials.username, password: credentials.password }),
            credentials: 'include',
        });
        if (!loginRes.ok) {
            let errorText = 'Login failed';
            try {
                const errorJson = await loginRes.json();
                if (errorJson && errorJson.error && errorJson.error.description) {
                    errorText = errorJson.error.description;
                }
            }
            catch {
                try {
                    const text = await loginRes.text();
                    if (text) {
                        errorText = text;
                    }
                }
                catch { }
            }
            throw new Error(errorText);
        }
        // Check if response is JSON or text
        const contentType = loginRes.headers.get('content-type');
        let result;
        if (contentType && contentType.includes('application/json')) {
            result = await loginRes.json();
        }
        else {
            // Handle text response (like "Login successful")
            const responseText = await loginRes.text();
            console.log('Server response:', responseText);
        }
        await this.updateToken({});
    }
    async updateToken(params) {
        try {
            // Ensure OAuth is configured first
            if (!this.openidConfigurationInfo) {
                await this.configureOAuth();
            }
            // Validation: اطمینان از وجود authConfig
            if (!this.aXMAuthConfigs.authConfig) {
                throw new Error('authConfig is missing. Please check your environment configuration.');
            }
            // get Token Code
            if (params['code']) {
                // If params contains 'code', exchange it for tokens using the OpenIddict token endpoint
                const code = params['code'];
                const redirectUri = params['redirectUri'] || this.aXMAuthConfigs.authConfig.redirectUri;
                const clientId = params['clientId'] || this.aXMAuthConfigs.authConfig.clientId;
                const tokenEndpoint = params['tokenEndpoint'] ||
                    this.openidConfigurationInfo?.info?.discoveryDocument?.token_endpoint ||
                    `${this.aXMAuthConfigs?.baseUrl}/connect/token`;
                // Get code_verifier from localStorage (PKCE)
                const codeVerifier = localStorage.getItem('pkce_code_verifier');
                localStorage.removeItem('pkce_code_verifier');
                if (!codeVerifier) {
                    throw new Error('Code verifier not found. Please try signing in again.');
                }
                // Prepare body for token request
                const body = new URLSearchParams({
                    grant_type: 'authorization_code',
                    client_id: clientId,
                    code_verifier: codeVerifier,
                    code: code,
                    redirect_uri: redirectUri,
                });
                // Call the token endpoint (OpenIddict)
                const response = await fetch(tokenEndpoint, {
                    method: 'POST',
                    headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
                    body: body.toString(),
                });
                if (!response.ok) {
                    throw new Error(`Token exchange failed: ${response.status} ${response.statusText}`);
                }
                const tokenData = await response.json();
                if (!tokenData) {
                    throw new Error('Token data not found');
                }
                const payload = JwtUtil.parseJwt(tokenData.id_token);
                if (!payload) {
                    throw new Error('Payload not found');
                }
                const user = {
                    id: payload['sub'] || payload['http://schemas.xmlsoap.org/ws/2005/05/identity/claims/nameidentifier'] || '',
                    title: payload['name'] || payload['email'] || '',
                    name: payload['name'] || payload['email'] || '',
                    avatar: payload['picture'] || '',
                };
                const tenant = payload['tenantid'] || payload['tenant']
                    ? {
                        id: payload['tenantid'] || payload['tenant'] || '',
                        name: payload['tenantname'] || '',
                        title: payload['tenanttitle'] || '',
                    }
                    : undefined;
                const application = payload['applicationid'] || payload['application']
                    ? {
                        id: payload['applicationid'] || payload['application'] || '',
                        name: payload['applicationname'] || '',
                        title: payload['applicationtitle'] || '',
                    }
                    : undefined;
                console.log('payload', payload);
                return {
                    succeed: true,
                    data: {
                        accessToken: tokenData.access_token,
                        refreshToken: tokenData.refresh_token,
                        idToken: tokenData.id_token,
                        expiresIn: TimeUtil.calculateExpireInDate(tokenData.expires_in || 0),
                        user,
                        tenant,
                        application,
                    },
                };
            }
            // get Authorizeation Code
            else {
                // Validation: اطمینان از وجود authConfig
                if (!this.aXMAuthConfigs.authConfig) {
                    throw new Error('authConfig is missing. Please check your environment configuration.');
                }
                // Extract parameters
                // Support both direct id fields and nested tenant/application objects
                const tenantId = params['tenantId'] ?? params['tenant']?.id ?? null;
                const applicationId = params['applicationId'] ?? params['application']?.id ?? null;
                const redirectUri = params['redirectUri'] || this.aXMAuthConfigs.authConfig.redirectUri;
                const scope = params['scope'] || this.aXMAuthConfigs.authConfig.scope;
                // Generate PKCE code verifier and challenge
                const codeVerifier = PkceUtil.generateRandomString(128);
                localStorage.setItem('pkce_code_verifier', codeVerifier);
                const codeChallenge = await PkceUtil.generateCodeChallenge(codeVerifier);
                // Build authorization URL
                const authorizeEndpoint = this.openidConfigurationInfo.info.discoveryDocument.authorization_endpoint;
                const clientId = this.aXMAuthConfigs.authConfig.clientId;
                const responseType = 'code';
                const state = Math.random().toString(36).substring(2);
                const queryParams = [
                    `response_type=${encodeURIComponent(responseType)}`,
                    `client_id=${encodeURIComponent(clientId)}`,
                    `redirect_uri=${encodeURIComponent(redirectUri)}`,
                    `scope=${encodeURIComponent(scope)}`,
                    `state=${encodeURIComponent(state)}`,
                    tenantId ? `tenant_id=${encodeURIComponent(tenantId)}` : null,
                    applicationId ? `application_id=${encodeURIComponent(applicationId)}` : null,
                    `code_challenge=${encodeURIComponent(codeChallenge)}`,
                    `code_challenge_method=S256`,
                ]
                    .filter(Boolean)
                    .join('&');
                const authorizeUrl = `${authorizeEndpoint}?${queryParams}`;
                window.location.href = authorizeUrl;
                // Prevent further execution by waiting on a never-resolving Promise after redirect
                await new Promise(() => { });
            }
        }
        catch (error) {
            this.handleError(error);
        }
    }
    /**
     * Signs out the user according to OpenID Connect standards.
     * Tries to call the standard OIDC end_session_endpoint if available, else falls back to configured logoutUrl.
     * Falls back to root landing page on local logout if nothing is provided.
     * This runs in the background (without redirecting user immediately to the endpoint).
     */
    async signout() {
        localStorage.removeItem('pkce_code_verifier');
        localStorage.removeItem('oauth_provider');
        // Standard OIDC logout: try to use end_session_endpoint if found in the discovery document
        const discoveryDoc = this.openidConfigurationInfo?.info?.discoveryDocument;
        let logoutUrl;
        if (discoveryDoc?.end_session_endpoint) {
            logoutUrl = discoveryDoc.end_session_endpoint;
            // Optional: append id_token_hint, post_logout_redirect_uri or others as needed by your IdP
            // For example: logoutUrl += `?post_logout_redirect_uri=${encodeURIComponent(window.location.origin)}`;
        }
        else if (this.aXMAuthConfigs.logoutUrl) {
            logoutUrl = this.aXMAuthConfigs.logoutUrl;
        }
        // Call logout in the background (don't redirect)
        if (logoutUrl) {
            // Fire-and-forget: Create an invisible iframe to make the logout request in the background
            const iframe = document.createElement('iframe');
            iframe.style.display = 'none';
            iframe.src = logoutUrl;
            document.body.appendChild(iframe);
            // Optionally, remove iframe after load
            iframe.onload = () => {
                setTimeout(() => document.body.removeChild(iframe), 1000);
            };
        }
        // Always send user to landing page after local logout, regardless
        window.location.href = '/';
    }
    async refreshToken(context) {
        try {
            await this.configureOAuth();
            if (!this.aXMAuthConfigs.authConfig || !this.aXMAuthConfigs.authConfig.clientId) {
                throw new Error('authConfig or clientId is missing');
            }
            const authData = this.loadAuthData();
            if (!authData) {
                return { succeed: false };
            }
            const refreshToken = authData.refreshToken;
            if (!refreshToken) {
                return { succeed: false };
            }
            const body = new HttpParams()
                .set('grant_type', 'refresh_token')
                .set('client_id', this.aXMAuthConfigs.authConfig.clientId)
                .set('refresh_token', refreshToken);
            const headers = new HttpHeaders().set('Content-Type', 'application/x-www-form-urlencoded');
            const response = await firstValueFrom(this.http.post(this.openidConfigurationInfo.info.discoveryDocument.token_endpoint, body.toString(), { headers }));
            // Extract user, tenant, and application from id_token
            const payload = JwtUtil.parseJwt(response.id_token);
            const user = {
                id: payload['sub'] || payload['http://schemas.xmlsoap.org/ws/2005/05/identity/claims/nameidentifier'] || '',
                title: payload['name'] || payload['email'] || '',
                name: payload['name'] || payload['email'] || '',
                avatar: payload['picture'] || '',
            };
            const tenant = payload['tenantid'] || payload['tenant']
                ? {
                    id: payload['tenantid'] || payload['tenant'] || '',
                    name: payload['tenantname'] || '',
                    title: payload['tenanttitle'] || '',
                }
                : undefined;
            const application = payload['applicationid'] || payload['application']
                ? {
                    id: payload['applicationid'] || payload['application'] || '',
                    name: payload['applicationname'] || '',
                    title: payload['applicationtitle'] || '',
                }
                : undefined;
            const sessionData = {
                accessToken: response.access_token,
                refreshToken: response.refresh_token,
                idToken: response.id_token,
                strategy: 'oidc',
                expiresIn: TimeUtil.calculateExpireInDate(response.expires_in ?? 0),
                user,
                tenant,
                application,
            };
            // this.setServiceProps(sessionData);
            return {
                succeed: true,
                data: {
                    ...sessionData,
                    user: sessionData.user, // Ensure user is not undefined
                },
            };
        }
        catch (error) {
            console.error('Error refreshing token', error);
            return { succeed: false };
        }
    }
    loadAuthData() {
        const sessionData = this.sessionService.getSessionData();
        return sessionData || undefined;
    }
    async loadUserInfo() {
        return this.oauthService.loadUserProfile();
    }
    handleError(error) {
        console.error('Authentication error:', error);
        throw error;
    }
    //#region getter
    get name() {
        return 'oidc';
    }
    static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: AXCAPIOidcStrategy, deps: null, target: i0.ɵɵFactoryTarget.Injectable }); }
    static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: AXCAPIOidcStrategy }); }
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: AXCAPIOidcStrategy, decorators: [{
            type: Injectable
        }] });

class AXMOidcPermissionLoader {
    constructor(http) {
        this.http = http;
        this.configs = inject(AXP_ROOT_CONFIG_TOKEN);
        this.apiGetConfig = `${this.configs.baseUrl}/abp/application-configuration`;
    }
    async getList(context) {
        const response = await firstValueFrom(this.http.get(this.apiGetConfig));
        return this.mapTo(response);
        // if (context.user == null)
        //   return [];
        // else if (context.user.name.toLowerCase() == 'admin')
        //   return ['axp.admin.console', 'asc.admin.message', 'asc.admin.settings', 'asc.admin.gliding', 'asc.user.gliding'];
        // else
        //   return ['asc.user.gliding'];
        // return ['axp.admin.console', 'asc.admin.message', 'asc.admin.settings', 'asc.admin.gliding', 'asc.user.gliding'];
    }
    mapTo(jsonObj) {
        const policies = jsonObj.auth.grantedPolicies;
        const truePolicies = Object.keys(policies).filter((key) => policies[key] === true);
        return truePolicies;
    }
    static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: AXMOidcPermissionLoader, deps: [{ token: i1.HttpClient }], target: i0.ɵɵFactoryTarget.Injectable }); }
    static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: AXMOidcPermissionLoader }); }
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: AXMOidcPermissionLoader, decorators: [{
            type: Injectable
        }], ctorParameters: () => [{ type: i1.HttpClient }] });

class AXMOidcTenantLoader {
    constructor(http) {
        this.http = http;
        this.configs = inject(AXP_ROOT_CONFIG_TOKEN);
        this.apiGetTenants = `${this.configs.baseUrl}/tenants/available-for-user`;
    }
    async getList(context) {
        const response = await firstValueFrom(this.http.get(this.apiGetTenants));
        return response.items.map((item) => {
            return this.mapToAXPTenant(item);
        });
    }
    async set(tenant) {
        return Promise.resolve();
    }
    mapToAXPTenant(item) {
        return {
            id: item.id,
            name: item.name || 'defaultName',
            title: item.title || 'defaultTitle',
            // Add other fields and defaults as needed, and handle the logo if applicable
        };
    }
    static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: AXMOidcTenantLoader, deps: [{ token: i1.HttpClient }], target: i0.ɵɵFactoryTarget.Injectable }); }
    static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: AXMOidcTenantLoader }); }
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: AXMOidcTenantLoader, decorators: [{
            type: Injectable
        }], ctorParameters: () => [{ type: i1.HttpClient }] });

class AXCApiUserAvatarProvider {
    constructor() {
        this.userService = inject(AXMUsersEntityService);
        this.sessionService = inject(AXPSessionService);
    }
    async provide(userId) {
        // Check if requesting current user info
        const currentUser = this.sessionService.user;
        const isCurrentUser = currentUser?.id === userId;
        if (isCurrentUser && currentUser) {
            // Use session service user data for current user
            const [firstName, lastName] = (currentUser.name || '').split(' ') || ['', ''];
            return {
                id: currentUser.id,
                username: currentUser.name || '',
                firstName: firstName || '',
                lastName: lastName || '',
                status: 'online',
                avatarUrl: currentUser.avatar || AXPDataGenerator.avatar(),
            };
        }
        // Use entity service for other users
        const user = await this.userService.getOne(userId);
        if (!user) {
            throw new Error(`User not found for ${userId}`);
        }
        const [firstName, lastName] = user.displayName.split(' ') || ['', ''];
        return {
            id: user.id,
            username: user.username,
            firstName: firstName || '',
            lastName: lastName || '',
            status: 'online',
            avatarUrl: AXPDataGenerator.avatar(),
        };
    }
}

//#region ----   Imports   ----
//#endregion
/**
 * API-based Report Viewer Service
 * Extends the base service to override data loading methods with API calls
 */
class AXCReportViewerApiService extends AXPReportViewerService {
    constructor() {
        super(...arguments);
        this.http = inject(HttpClient);
        this.configs = inject(AXP_ROOT_CONFIG_TOKEN);
        this.baseUrl = this.configs.baseUrl;
    }
    //#region ----   Override: Category Loading   ----
    /**
     * Override: Load categories from API instead of entity service
     */
    async loadCategories(parentId) {
        try {
            let url;
            if (parentId) {
                url = `${this.baseUrl}/v1/global/report-management/category/${parentId}`;
                const response = await firstValueFrom(this.http.get(url));
                const categoryData = response.items?.[0];
                const filteredItems = categoryData?.folderItems ?? [];
                return filteredItems.map((item) => this.mapApiCategoryToReportCategory(item));
            }
            else {
                url = `${this.baseUrl}/v1/global/report-management/category`;
                const params = { Skip: 0, Take: 1000 };
                const response = await firstValueFrom(this.http.get(url, { params }));
                const all = response.items ?? [];
                const rootCategories = all.filter((i) => !i.reportCategoryParentId);
                return rootCategories.map((item) => this.mapApiCategoryToReportCategory(item));
            }
        }
        catch (error) {
            console.error('Error fetching report categories:', error);
            return [];
        }
    }
    //#endregion
    //#region ----   Override: Report Loading   ----
    /**
     * Override: Load reports from API instead of entity service
     */
    async loadReports(categoryId) {
        try {
            const url = `${this.baseUrl}/v1/global/report-management/category/${categoryId}`;
            const response = await firstValueFrom(this.http.get(url));
            const categoryData = response.items?.[0];
            const defs = categoryData?.reportDefinitionItems ?? [];
            // Fetch full report definitions for each item to get layouts and parameterGroups
            const fullDefinitions = await Promise.all(defs.map(async (item) => {
                try {
                    const reportUrl = `${this.baseUrl}/v1/global/report-management/report/${item.id}`;
                    const reportResponse = await firstValueFrom(this.http.get(reportUrl));
                    return this.mapApiReportDefinitionToReportDefinition(reportResponse);
                }
                catch {
                    // Fallback to item mapping if full fetch fails
                    return this.mapApiReportDefinitionItemToReportDefinition(item);
                }
            }));
            return fullDefinitions;
        }
        catch (error) {
            console.error('Error fetching report definitions:', error);
            return [];
        }
    }
    /**
     * Override: Load single report from API instead of entity service
     */
    async loadReport(id) {
        try {
            const url = `${this.baseUrl}/v1/global/report-management/report/${id}`;
            const response = await firstValueFrom(this.http.get(url));
            return this.mapApiReportDefinitionToReportDefinition(response);
        }
        catch (error) {
            console.error('Error fetching report definition by ID:', error);
            return undefined;
        }
    }
    //#endregion
    //#region ----   Override: Report Execution   ----
    /**
     * Override: Execute report with given context
     * Implements report execution logic for API environment
     * TODO: Implement API call to execute report
     */
    async executeReport(context) {
        // TODO: Implement API call to execute report
        // Example:
        // const url = `${this.baseUrl}/v1/global/report-management/report/${context.reportId}/execute`;
        // const response = await firstValueFrom(this.http.post<AXPExecutionReportCommandResult>(url, context));
        // return response;
        throw new Error('executeReport API implementation is not yet implemented');
    }
    //#endregion
    //#region ----   Private: Mapping Methods   ----
    mapApiCategoryToReportCategory(apiItem) {
        return {
            id: apiItem.id,
            title: apiItem.title,
            description: apiItem.description || undefined,
            parentId: apiItem.reportCategoryParentId || undefined,
            childrenCount: apiItem.folderCount ?? 0,
            itemsCount: apiItem.itemCount ?? 0,
        };
    }
    mapApiReportDefinitionItemToReportDefinition(apiItem) {
        return {
            id: apiItem.id,
            title: apiItem.title,
            description: apiItem.description || undefined,
            categoryIds: apiItem.categoryIds,
            parameterGroups: [],
            layouts: [],
            defaultLayoutId: '',
        };
    }
    mapApiReportDefinitionToReportDefinition(apiResponse) {
        return {
            id: apiResponse.id,
            title: apiResponse.title,
            description: apiResponse.description || undefined,
            categoryIds: apiResponse.categoryIds,
            parameterGroups: apiResponse.parameterGroups.map((group) => ({
                name: group.name,
                title: group.title,
                parameters: group.parameters.map((param) => ({
                    path: param.path,
                    title: param.title,
                    description: param.description,
                    widget: {
                        type: param.widget.type,
                        options: param.widget.options || {},
                        valueTransforms: param.widget.valueTransforms || {},
                    },
                })),
            })),
            layouts: apiResponse.layouts.map((layout) => ({
                id: layout.id,
                title: layout.title,
                layout: layout.layout,
                dataSource: layout.dataSource,
                export: layout.export,
                isDefault: layout.isDefault || false,
            })),
            defaultLayoutId: apiResponse.defaultLayoutId,
        };
    }
    static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: AXCReportViewerApiService, deps: null, target: i0.ɵɵFactoryTarget.Injectable }); }
    static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: AXCReportViewerApiService, providedIn: 'root' }); }
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: AXCReportViewerApiService, decorators: [{
            type: Injectable,
            args: [{
                    providedIn: 'root',
                }]
        }] });

class AXCReportManagementApiModule {
    static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: AXCReportManagementApiModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule }); }
    static { this.ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "14.0.0", version: "20.3.19", ngImport: i0, type: AXCReportManagementApiModule, imports: [AXPRuntimeModule] }); }
    static { this.ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: AXCReportManagementApiModule, providers: [
            {
                provide: AXPReportViewerService,
                useClass: AXCReportViewerApiService,
            },
            provideCommandSetups([
                {
                    key: 'ReportManagement.Report:Execute',
                    command: () => import('./acorex-connectivity-api-execute.command-D2Q0ahw4.mjs').then((c) => c.AXCReportExecuteCommand),
                }
            ]),
        ], imports: [AXPRuntimeModule] }); }
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: AXCReportManagementApiModule, decorators: [{
            type: NgModule,
            args: [{
                    imports: [AXPRuntimeModule],
                    exports: [],
                    declarations: [],
                    providers: [
                        {
                            provide: AXPReportViewerService,
                            useClass: AXCReportViewerApiService,
                        },
                        provideCommandSetups([
                            {
                                key: 'ReportManagement.Report:Execute',
                                command: () => import('./acorex-connectivity-api-execute.command-D2Q0ahw4.mjs').then((c) => c.AXCReportExecuteCommand),
                            }
                        ]),
                    ],
                }]
        }] });

class AXCApiModule {
    static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: AXCApiModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule }); }
    static { this.ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "14.0.0", version: "20.3.19", ngImport: i0, type: AXCApiModule, imports: [i1$1.OAuthModule, i2.AXPAuthModule, AXCUtilsModule,
            AXCReportManagementApiModule] }); }
    static { this.ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: AXCApiModule, providers: [
            {
                provide: AXPEntityStorageService,
                useClass: AXCApiEntityStorageService,
            },
            {
                provide: AXPFileStorageService,
                useClass: AXCFileStorageApiService,
            },
            {
                provide: AXP_TENANT_LOADER,
                useClass: AXMOidcTenantLoader,
            },
            {
                provide: AXP_APPLICATION_LOADER,
                useClass: AXMOidcApplicationLoader,
            },
            {
                provide: AXP_PERMISSION_LOADER,
                useClass: AXMOidcPermissionLoader,
            },
            {
                provide: AXP_FEATURE_LOADER,
                useClass: AXMOidcFeatureLoader,
            },
            {
                provide: STRATEGY_CONFIG_TOKEN,
                useValue: {
                    selectValueStrategy: 'valueField',
                    lookupValueStrategy: 'valueField',
                },
            },
            {
                provide: AXP_USER_AVATAR_PROVIDER,
                useClass: AXCApiUserAvatarProvider,
            },
        ], imports: [OAuthModule.forRoot(),
            AXPAuthModule.forRoot({
                strategies: [AXCAPIOidcStrategy],
            }),
            AXCUtilsModule,
            AXCReportManagementApiModule] }); }
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: AXCApiModule, decorators: [{
            type: NgModule,
            args: [{
                    imports: [
                        OAuthModule.forRoot(),
                        AXPAuthModule.forRoot({
                            strategies: [AXCAPIOidcStrategy],
                        }),
                        AXCUtilsModule,
                        AXCReportManagementApiModule,
                    ],
                    providers: [
                        {
                            provide: AXPEntityStorageService,
                            useClass: AXCApiEntityStorageService,
                        },
                        {
                            provide: AXPFileStorageService,
                            useClass: AXCFileStorageApiService,
                        },
                        {
                            provide: AXP_TENANT_LOADER,
                            useClass: AXMOidcTenantLoader,
                        },
                        {
                            provide: AXP_APPLICATION_LOADER,
                            useClass: AXMOidcApplicationLoader,
                        },
                        {
                            provide: AXP_PERMISSION_LOADER,
                            useClass: AXMOidcPermissionLoader,
                        },
                        {
                            provide: AXP_FEATURE_LOADER,
                            useClass: AXMOidcFeatureLoader,
                        },
                        {
                            provide: STRATEGY_CONFIG_TOKEN,
                            useValue: {
                                selectValueStrategy: 'valueField',
                                lookupValueStrategy: 'valueField',
                            },
                        },
                        {
                            provide: AXP_USER_AVATAR_PROVIDER,
                            useClass: AXCApiUserAvatarProvider,
                        },
                    ],
                }]
        }] });

//#region ----   Class Definition   ----
class APIGoogleStrategy extends AXPAuthStrategy {
    constructor() {
        super();
        this.aXMAuthConfigs = inject(AXM_AUTH_CONFIG_TOKEN);
        this.oauthService = inject(OAuthService);
        this.http = inject(HttpClient);
        this.sessionService = inject(AXPSessionService);
        this.router = inject(Router);
        this.externalAuthorizationService = inject(AXCExternalAuthorizationService);
        this.tenantLoader = inject(AXP_TENANT_LOADER);
        this.applicationLoader = inject(AXP_APPLICATION_LOADER);
    }
    get name() {
        return 'google';
    }
    async configureOAuth() {
        if (this.openidConfigurationInfo)
            return;
        if (!this.authConfig) {
            if (!this.aXMAuthConfigs.authConfig) {
                throw new Error('authConfig is missing');
            }
            this.authConfig = this.aXMAuthConfigs.authConfig;
        }
        this.oauthService.configure(this.authConfig);
        this.oauthService.setStorage(localStorage);
        this.openidConfigurationInfo = await this.oauthService.loadDiscoveryDocument();
        if (!this.openidConfigurationInfo) {
            throw new Error('openidConfigurationInfo is missing');
        }
        this.oauthService.events.subscribe(async (event) => {
            // console.log('event', event);
            // if (event.type === 'token_received') {
            //   console.log('Token has been refreshed');
            // }
            // if (event.type === 'token_expires') {
            //   console.log('Token is about to expire. Triggering silent refresh...');
            // }
        });
        const oidcJson = localStorage.getItem(AXPSessionService.SESSION_KEY);
        if (oidcJson) {
            const authData = JSON.parse(oidcJson);
            if (authData) {
                this.sessionService.setSession(authData);
                if (authData.expiresIn && new Date(authData.expiresIn) < new Date()) {
                    if (authData.expiresIn) {
                        this.sessionService.refreshToken();
                    }
                    else {
                        this.signout();
                    }
                }
            }
        }
    }
    async signin(credentials) {
        const providerName = credentials['strategy'];
        await this.externalAuthorizationService.signin(providerName);
    }
    async signout() {
        localStorage.removeItem('pkce_code_verifier');
        localStorage.removeItem('oauth_provider');
        console.log('User signed out');
    }
    async refreshToken(context) {
        try {
            await this.configureOAuth();
            if (!this.authConfig || !this.authConfig.clientId) {
                throw new Error('authConfig or clientId is missing');
            }
            const authData = this.loadAuthData();
            if (!authData) {
                return { succeed: false };
            }
            const refreshToken = authData.refreshToken;
            if (!refreshToken) {
                return { succeed: false };
            }
            const body = new URLSearchParams({
                grant_type: 'refresh_token',
                client_id: this.authConfig.clientId,
                refresh_token: refreshToken,
            });
            const response = await fetch(this.openidConfigurationInfo.info.discoveryDocument.token_endpoint, {
                method: 'POST',
                headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
                body: body.toString(),
            });
            if (!response.ok) {
                throw new Error(`Token refresh failed: ${response.status} ${response.statusText}`);
            }
            const tokenData = await response.json();
            // Extract user information from the refreshed token
            const payload = JwtUtil.parseJwt(tokenData.id_token);
            const user = {
                id: payload['sub'] || '',
                title: payload['name'] || payload['email'] || '',
                name: payload['name'] || payload['email'] || '',
                avatar: payload['picture'] || '',
            };
            const tenant = payload['tenantid'] || payload['tenant']
                ? {
                    id: payload['tenantid'] || payload['tenant'] || '',
                    name: payload['tenantname'] || '',
                    title: payload['tenanttitle'] || '',
                }
                : undefined;
            const application = payload['applicationid'] || payload['application']
                ? {
                    id: payload['applicationid'] || payload['application'] || '',
                    name: payload['applicationname'] || '',
                    title: payload['applicationtitle'] || '',
                }
                : undefined;
            const sessionData = {
                accessToken: tokenData.access_token,
                refreshToken: tokenData.refresh_token,
                idToken: tokenData.id_token,
                strategy: 'google',
                expiresIn: TimeUtil.calculateExpireInDate(tokenData.expires_in || 0),
                user,
                tenant,
                application,
            };
            return {
                succeed: true,
                data: {
                    ...sessionData,
                    user: sessionData.user,
                },
            };
        }
        catch (error) {
            console.error('Error refreshing token', error);
            return { succeed: false };
        }
    }
    async updateToken(params) {
        try {
            // Ensure OAuth is configured first
            if (!this.openidConfigurationInfo) {
                await this.configureOAuth();
            }
            // If params contains 'code', exchange it for tokens
            if (params['code']) {
                const code = params['code'];
                const redirectUri = params['redirectUri'] || this.authConfig.redirectUri;
                const clientId = params['clientId'] || this.authConfig.clientId;
                const tokenEndpoint = this.openidConfigurationInfo.info.discoveryDocument.token_endpoint;
                // Get code_verifier from localStorage (PKCE)
                const codeVerifier = localStorage.getItem('pkce_code_verifier');
                localStorage.removeItem('pkce_code_verifier');
                if (!codeVerifier) {
                    throw new Error('Code verifier not found. Please try signing in again.');
                }
                // Prepare body for token request
                const body = new URLSearchParams({
                    grant_type: 'authorization_code',
                    client_id: clientId,
                    code_verifier: codeVerifier,
                    code: code,
                    redirect_uri: redirectUri,
                });
                // Call the token endpoint
                const response = await fetch(tokenEndpoint, {
                    method: 'POST',
                    headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
                    body: body.toString(),
                });
                if (!response.ok) {
                    throw new Error(`Token exchange failed: ${response.status} ${response.statusText}`);
                }
                const tokenData = await response.json();
                if (!tokenData) {
                    throw new Error('Token data not found');
                }
                // Parse the ID token to extract user information
                const payload = JwtUtil.parseJwt(tokenData.id_token);
                if (!payload) {
                    throw new Error('Payload not found');
                }
                const user = {
                    id: payload['sub'] || '',
                    title: payload['name'] || payload['email'] || '',
                    name: payload['name'] || payload['email'] || '',
                    avatar: payload['picture'] || '',
                };
                const tenant = payload['tenantid'] || payload['tenant']
                    ? {
                        id: payload['tenantid'] || payload['tenant'] || '',
                        name: payload['tenantname'] || '',
                        title: payload['tenanttitle'] || '',
                    }
                    : undefined;
                const application = payload['applicationid'] || payload['application']
                    ? {
                        id: payload['applicationid'] || payload['application'] || '',
                        name: payload['applicationname'] || '',
                        title: payload['applicationtitle'] || '',
                    }
                    : undefined;
                return {
                    succeed: true,
                    data: {
                        accessToken: tokenData.access_token,
                        refreshToken: tokenData.refresh_token,
                        idToken: tokenData.id_token,
                        expiresIn: TimeUtil.calculateExpireInDate(tokenData.expires_in || 0),
                        user,
                        tenant,
                        application,
                    },
                };
            }
            // get Authorizeation Code
            else {
                // Extract parameters
                // Support both direct id fields and nested tenant/application objects
                const tenantId = params['tenantId'] ?? params['tenant']?.id ?? null;
                const applicationId = params['applicationId'] ?? params['application']?.id ?? null;
                const redirectUri = params['redirectUri'] || this.authConfig.redirectUri;
                const scope = params['scope'] || this.authConfig.scope;
                // Generate PKCE code verifier and challenge
                const codeVerifier = PkceUtil.generateRandomString(128);
                localStorage.setItem('pkce_code_verifier', codeVerifier);
                const codeChallenge = await PkceUtil.generateCodeChallenge(codeVerifier);
                // Build authorization URL
                const authorizeEndpoint = this.openidConfigurationInfo.info.discoveryDocument.authorization_endpoint;
                const clientId = this.authConfig.clientId;
                const responseType = 'code';
                const state = Math.random().toString(36).substring(2);
                const queryParams = [
                    `response_type=${encodeURIComponent(responseType)}`,
                    `client_id=${encodeURIComponent(clientId)}`,
                    `redirect_uri=${encodeURIComponent(redirectUri)}`,
                    `scope=${encodeURIComponent(scope)}`,
                    `state=${encodeURIComponent(state)}`,
                    tenantId ? `tenant_id=${encodeURIComponent(tenantId)}` : null,
                    applicationId ? `application_id=${encodeURIComponent(applicationId)}` : null,
                    `code_challenge=${encodeURIComponent(codeChallenge)}`,
                    `code_challenge_method=S256`,
                ]
                    .filter(Boolean)
                    .join('&');
                const authorizeUrl = `${authorizeEndpoint}?${queryParams}`;
                window.location.href = authorizeUrl;
                await new Promise(() => { });
                return;
            }
        }
        catch (error) {
            console.error('Error in updateToken:', error);
            throw error;
        }
    }
    loadAuthData() {
        const sessionData = this.sessionService.getSessionData();
        return sessionData || undefined;
    }
    handleError(error) {
        console.error('Authentication error:', error);
        throw error;
    }
    static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: APIGoogleStrategy, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
    static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: APIGoogleStrategy }); }
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: APIGoogleStrategy, decorators: [{
            type: Injectable
        }], ctorParameters: () => [] });

//#region ----   Execute Report DTO   ----
//#endregion

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

export { APIGoogleStrategy, AXCAPIOidcStrategy, AXCApiEntityStorageService, AXCApiModule, AXCApiUserAvatarProvider, AXCReportManagementApiModule, AXMConfigurationService, AXMOidcApplicationLoader, AXMOidcFeatureLoader, AXMOidcPermissionLoader, AXMOidcTenantLoader };
//# sourceMappingURL=acorex-connectivity-api.mjs.map
