import { HttpErrorResponse, HttpStatusCode } from '@angular/common/http';
import { Injectable } from '@angular/core';
import { marker as _ } from '@biesbjerg/ngx-translate-extract-marker';
import { EntitiesService, Toaster } from '@iqser/common-ui';
import { List, mapEach } from '@iqser/common-ui/lib/utils';
import { DossierTemplate, IDossierTemplate } from '@red/domain';
import { firstValueFrom, forkJoin, Observable, of } from 'rxjs';
import { catchError, map, switchMap, tap } from 'rxjs/operators';
import { DictionaryService } from '../entity-services/dictionary.service';
import { DossierTemplateStatsService } from '../entity-services/dossier-template-stats.service';
import { FileAttributesService } from '../entity-services/file-attributes.service';

const DOSSIER_TEMPLATE_CONFLICT_MSG = _('dossier-templates-listing.error.conflict');
const GENERIC_MSG = _('dossier-templates-listing.error.generic');

@Injectable({
    providedIn: 'root',
})
export class DossierTemplatesService extends EntitiesService<IDossierTemplate, DossierTemplate> {
    protected readonly _defaultModelPath = 'dossier-template';
    protected readonly _entityClass = DossierTemplate;

    constructor(
        private readonly _toaster: Toaster,
        private readonly _fileAttributesService: FileAttributesService,
        private readonly _dossierTemplateStatsService: DossierTemplateStatsService,
        private readonly _dictionaryService: DictionaryService,
    ) {
        super();
    }

    loadAll(): Observable<DossierTemplate[]> {
        const dossierTemplateIds = (templates: DossierTemplate[]) => templates.map(d => d.id);

        return this.getAll().pipe(
            mapEach(entity => new DossierTemplate(entity)),
            /* Load stats before updating entities */
            switchMap(templates => {
                if (templates.length) {
                    return this._dossierTemplateStatsService.getFor(dossierTemplateIds(templates)).pipe(map(() => templates));
                }
                return of(templates);
            }),
            tap(templates => this.setEntities(templates)),
        );
    }

    loadDossierTemplate(dossierTemplateId: string) {
        return this._getOne([dossierTemplateId], this._defaultModelPath).pipe(
            map(entity => new DossierTemplate(entity)),
            switchMap(template => this._dossierTemplateStatsService.getFor([dossierTemplateId]).pipe(map(() => template))),
            tap(template => this.addEntity(template)),
        );
    }

    delete(body: List): Observable<boolean> {
        const showToast = (error: HttpErrorResponse) => {
            if (error.status === HttpStatusCode.Conflict) {
                this._toaster.error(DOSSIER_TEMPLATE_CONFLICT_MSG);
            } else {
                this._toaster.error(GENERIC_MSG);
            }
            return of(true);
        };

        return super._post(body, `${this._defaultModelPath}/delete`).pipe(
            catchError(showToast),
            switchMap(error => (error ? of(false) : this.loadAll().pipe(map(() => true)))),
        );
    }

    async createOrUpdate(body: IDossierTemplate) {
        const dossierTemplate = await firstValueFrom(this._post(body));
        await firstValueFrom(this.loadAll());
        return this.find(dossierTemplate.dossierTemplateId);
    }

    async clone(dossierTemplateId: string, body: IDossierTemplate) {
        const dossierTemplate = await firstValueFrom(this._post(body, `${this._defaultModelPath}/${dossierTemplateId}/clone`));
        await firstValueFrom(this.loadAll());
        return this.find(dossierTemplate.dossierTemplateId);
    }

    refreshDossierTemplate(dossierTemplateId: string): Observable<any> {
        return forkJoin([
            this._fileAttributesService.loadFileAttributesConfig(dossierTemplateId),
            this._dictionaryService.loadDictionaryDataForDossierTemplate(dossierTemplateId),
        ]);
    }
}
