import { Injectable } from '@angular/core';
import { EntitiesService, isArray, QueryParam } from '@iqser/common-ui';
import { List, mapEach } from '@iqser/common-ui/lib/utils';
import { File, IFile } from '@red/domain';
import { UserService } from '@users/user.service';
import { NGXLogger } from 'ngx-logger';
import { firstValueFrom } from 'rxjs';
import { map, switchMap, tap } from 'rxjs/operators';
import { DossierStatsService } from '../dossiers/dossier-stats.service';
import { FilesMapService } from './files-map.service';

const asList = <T>(value: T | List<T>): List<T> => (isArray(value) ? value : [value]);

@Injectable({
    providedIn: 'root',
})
export class FilesService extends EntitiesService<IFile, File> {
    protected readonly _defaultModelPath = 'status';
    protected readonly _entityClass = File;

    constructor(
        protected readonly _logger: NGXLogger,
        private readonly _userService: UserService,
        private readonly _filesMapService: FilesMapService,
        private readonly _dossierStatsService: DossierStatsService,
    ) {
        super();
    }

    /** Reload dossier files + stats. */
    loadAll(dossierId: string) {
        const files$ = this.getFor(dossierId).pipe(
            mapEach(file => new File(file, this._userService.getName(file.assignee))),
            tap(file => this._logger.info('[FILE] Loaded', file)),
        );
        const loadStats$ = files$.pipe(switchMap(files => this._dossierStatsService.getFor([dossierId]).pipe(map(() => files))));
        return loadStats$.pipe(tap(files => this._filesMapService.set(dossierId, files)));
    }

    async reload(dossierId: string, file: File) {
        const _file = await firstValueFrom(super._getOne([dossierId, file.id]));
        const reloadedFile = new File(_file, this._userService.getName(_file.assignee));
        await firstValueFrom(this._dossierStatsService.getFor([dossierId]));
        this._logger.info('[FILE] Reloaded', reloadedFile);
        return this._filesMapService.replace(dossierId, [reloadedFile]);
    }

    async setAssignee(files: File | List<File>, assigneeId: string) {
        const _files = asList(files);
        const url = `${this._defaultModelPath}/set-assignee/${_files[0].dossierId}/bulk`;
        return this.#makePost(_files, url, [{ key: 'assigneeId', value: assigneeId }]);
    }

    async setToNew(files: File | List<File>) {
        const _files = asList(files);
        return this.#makePost(_files, `${this._defaultModelPath}/new/${_files[0].dossierId}/bulk`);
    }

    async setUnderApproval(files: File | List<File>, assigneeId: string) {
        const _files = asList(files);
        const url = `${this._defaultModelPath}/under-approval/${_files[0].dossierId}/bulk`;
        return this.#makePost(_files, url, [{ key: 'assigneeId', value: assigneeId }]);
    }

    async setReviewer(files: File | List<File>, assigneeId: string) {
        const _files = asList(files);
        const url = `${this._defaultModelPath}/under-review/${_files[0].dossierId}/bulk`;
        return this.#makePost(_files, url, [{ key: 'assigneeId', value: assigneeId }]);
    }

    async setApproved(files: File | List<File>) {
        const _files = asList(files);
        return this.#makePost(_files, `${this._defaultModelPath}/approved/${_files[0].dossierId}/bulk`);
    }

    async setUnderReview(files: File | List<File>) {
        const _files = asList(files);
        return this.#makePost(_files, `${this._defaultModelPath}/under-review/${_files[0].dossierId}/bulk`);
    }

    async #makePost(files: List<File>, url: string, queryParams?: List<QueryParam>) {
        const fileIds = files.map(f => f.id);
        await firstValueFrom(this._post(fileIds, url, queryParams));
        return firstValueFrom(this.loadAll(files[0].dossierId));
    }
}
