import { inject, Injectable } from '@angular/core';
import { GenericService } from '@iqser/common-ui';
import { IPermissionsMapping, PermissionsMapping } from '@red/domain';
import { firstValueFrom, Observable } from 'rxjs';
import { switchMap, tap } from 'rxjs/operators';
import { PermissionsConfigurationMapService } from './permissions-configuration-map.service';
import { PermissionsMapService } from './permissions-map.service';
import { mapEach } from '@iqser/common-ui/lib/utils';

@Injectable({
    providedIn: 'root',
})
export class EntityPermissionsService extends GenericService<IPermissionsMapping> {
    readonly #permissionsConfigurationMapService = inject(PermissionsConfigurationMapService);
    readonly #permissionsMapService = inject(PermissionsMapService);
    protected readonly _defaultModelPath = 'permissions';

    loadConfigFor(targetObject: string): Observable<PermissionsMapping[]> {
        return this._http.get<IPermissionsMapping[]>(`/${this._serviceName}/${this._defaultModelPath}/${targetObject}/mapping`).pipe(
            mapEach(mapping => new PermissionsMapping(mapping)),
            tap(mappings => this.#permissionsConfigurationMapService.set(targetObject, mappings)),
        );
    }

    loadFor(targetObject: string): Observable<PermissionsMapping[]> {
        return this._http.get<IPermissionsMapping[]>(`/${this._serviceName}/${this._defaultModelPath}/${targetObject}`).pipe(
            mapEach(mapping => new PermissionsMapping(mapping)),
            tap(mappings => {
                this.#addMissingPermissions(mappings, targetObject);
                this.#permissionsMapService.set(targetObject, mappings);
            }),
        );
    }

    async togglePermission(targetObject: string, targetPermission: string, changedPermission: string): Promise<PermissionsMapping[]> {
        const config = this.#permissionsConfigurationMapService.get(targetObject);
        const targetPermissionConfig = config.find(p => p.searchKey === targetPermission);
        const permissions = this.#permissionsMapService.get(targetObject);
        const currentTargetPermissionValues = this.#permissionsMapService.get(targetObject, targetPermission);
        const index = currentTargetPermissionValues.mappedPermissions.findIndex(p => p.name === changedPermission);
        if (index !== -1) {
            currentTargetPermissionValues.mappedPermissions.splice(index, 1);
        } else {
            const permission = targetPermissionConfig.mappedPermissions.find(p => p.name === changedPermission);
            currentTargetPermissionValues.mappedPermissions.push(permission);
        }
        const request = this._post(permissions, `${this._defaultModelPath}/${targetObject}`);
        return firstValueFrom(request.pipe(switchMap(() => this.loadFor(targetObject))));
    }

    #addMissingPermissions(mappings: PermissionsMapping[], targetObject: string): void {
        const configuration = this.#permissionsConfigurationMapService.get(targetObject);
        for (const mapping of configuration) {
            const targetPermission: string = mapping.targetPermission.name;
            if (!mappings.some(p => p.targetPermission.name === targetPermission)) {
                const missingConfig: PermissionsMapping = new PermissionsMapping({
                    mappedPermissions: [],
                    targetPermission: mapping.targetPermission,
                });
                mappings.push(missingConfig);
            }
        }
    }
}
