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 { DefaultColorsService } from '@services/entity-services/default-colors.service';
import { WatermarkService } from '@services/entity-services/watermark.service';
import { firstValueFrom, forkJoin, Observable, of } from 'rxjs';
import { catchError, map, mapTo, 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,
        private readonly _defaultColorsService: DefaultColorsService,
        private readonly _watermarksService: WatermarkService,
    ) {
        super();
    }

    loadAll(): Observable<DossierTemplate[]> {
        const getAttributes = (entities: DossierTemplate[]) =>
            entities.map(e => this._fileAttributesService.loadFileAttributesConfig(e.id));
        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 forkJoin([
                        this._dossierTemplateStatsService.getFor(dossierTemplateIds(templates)),
                        ...getAttributes(templates),
                        // TODO: this should be removed and called only when needed
                        this._dictionaryService.loadDictionaryData(dossierTemplateIds(templates)),
                        // TODO: this should be removed and called only when needed
                        this._defaultColorsService.loadAll(dossierTemplateIds(templates)),
                        // TODO: this should be removed and called only when needed
                        this._watermarksService.loadAll(dossierTemplateIds(templates)),
                    ]).pipe(map(() => templates));
                }
                return of(templates);
            }),
            tap(templates => this.setEntities(templates)),
        );
    }

    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(mapTo(true)))),
        );
    }

    async createOrUpdate(body: IDossierTemplate) {
        await firstValueFrom(this._post(body));
        return await firstValueFrom(this.loadAll());
    }

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

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