import { Injectable } from '@angular/core';
import { GenericService } from '@iqser/common-ui';
import { Dossier, IMatchedDocument, ISearchInput, ISearchRequest, ISearchResponse } from '@red/domain';
import { Observable, of, zip } from 'rxjs';
import { map, switchMap } from 'rxjs/operators';
import { FilesMapService } from '../files/files-map.service';
import { FilesService } from '../files/files.service';
import { DossiersCacheService } from '../dossiers/dossiers-cache.service';

@Injectable({ providedIn: 'root' })
export class PlatformSearchService extends GenericService<ISearchResponse> {
    protected readonly _defaultModelPath = 'search-v2';

    constructor(
        private readonly _filesService: FilesService,
        private readonly _dossiersCacheService: DossiersCacheService,
        private readonly _filesMapService: FilesMapService,
    ) {
        super();
    }

    search({
        dossierIds,
        dossierTemplateIds,
        workflowStatus,
        assignee,
        query,
        includeDeletedDossiers,
        includeArchivedDossiers,
    }: ISearchInput): Observable<ISearchResponse> {
        if (!query) {
            return of({
                matchedDocuments: [],
                total: 0,
            });
        }

        const body: ISearchRequest = {
            dossierIds,
            dossierTemplateIds,
            workflowStatus,
            assignee,
            queryString: query ?? '',
            page: 0,
            returnSections: false,
            pageSize: 300,
            includeDeletedDossiers,
            includeArchivedDossiers,
        };

        return this._post(body).pipe(switchMap(searchValue => this._loadMissingFiles$(searchValue)));
    }

    private _dossiersWithMissingFiles(searchResponse: ISearchResponse): Dossier[] {
        const documentsOfType = searchResponse.matchedDocuments.filter(document => this._dossiersCacheService.get(document.dossierId));
        const fileNotLoaded = ({ dossierId, fileId }: IMatchedDocument) => !this._filesMapService.get(dossierId, fileId);
        const dossiersWithNotLoadedFiles = documentsOfType.filter(fileNotLoaded).map(document => document.dossierId);
        return Array.from(new Set(dossiersWithNotLoadedFiles)).map(dossierId => this._dossiersCacheService.get(dossierId));
    }

    private _loadMissingFiles$(searchResponse: ISearchResponse): Observable<ISearchResponse> {
        const dossiers = this._dossiersWithMissingFiles(searchResponse);
        return dossiers.length ? this._loadFilesFor$(dossiers).pipe(map(() => searchResponse)) : of(searchResponse);
    }

    private _loadFilesFor$(dossiers: Dossier[]) {
        return zip(...dossiers.map(dossier => this._filesService.loadAll(dossier.id)));
    }
}
