import { EntitiesService, Toaster } from '@iqser/common-ui';
import { Dossier, DossierStats, IDossier, IDossierChanges, IDossierRequest } from '@red/domain';
import { Observable, of, Subject } from 'rxjs';
import { catchError, map, switchMap, tap } from 'rxjs/operators';
import { inject } from '@angular/core';
import { DossierStatsService } from './dossier-stats.service';
import { HttpErrorResponse, HttpStatusCode } from '@angular/common/http';
import { marker as _ } from '@biesbjerg/ngx-translate-extract-marker';
import { DashboardStatsService } from '../dossier-templates/dashboard-stats.service';
import { mapEach } from '@iqser/common-ui/lib/utils';

const CONFLICT_MSG = _('add-dossier-dialog.errors.dossier-already-exists');
const GENERIC_MSG = _('add-dossier-dialog.errors.generic');

export abstract class DossiersService extends EntitiesService<IDossier, Dossier> {
    protected readonly _dossierStatsService = inject(DossierStatsService);
    protected readonly _dashboardStatsService = inject(DashboardStatsService);
    protected readonly _toaster = inject(Toaster);
    protected readonly _entityClass = Dossier;
    protected abstract readonly _defaultModelPath: string;
    readonly dossierFileChanges$ = new Subject<string>();
    abstract readonly routerPath: string;

    createOrUpdate(dossier: IDossierRequest): Observable<Dossier> {
        const showToast = (error: HttpErrorResponse) => {
            this._toaster.error(error.status === HttpStatusCode.Conflict ? CONFLICT_MSG : GENERIC_MSG);
            return of(null);
        };

        return this._post(dossier, 'dossier').pipe(
            switchMap(newDossier => this.loadAll().pipe(map(() => this.find(newDossier.dossierId)))),
            catchError(showToast),
        );
    }

    loadAll(): Observable<Dossier[]> {
        const dossierIds = (dossiers: Dossier[]) => dossiers.map(d => d.id);
        return this.getAll().pipe(
            mapEach(entity => new Dossier(entity)),
            /* Load stats before updating entities */
            switchMap(dossiers => this._dossierStatsService.getFor(dossierIds(dossiers)).pipe(map(() => dossiers))),
            switchMap(dossiers => this._dashboardStatsService.loadAll().pipe(map(() => dossiers))),
            tap(dossiers => this.setEntities(dossiers)),
        );
    }

    updateDossier(dossier: Dossier): Observable<DossierStats[]> {
        this.replace(dossier);
        return this._dossierStatsService.getFor([dossier.id]);
    }

    emitFileChanges(dossierChanges: IDossierChanges): void {
        dossierChanges.filter(change => change.fileChanges).forEach(change => this.dossierFileChanges$.next(change.dossierId));
    }
}
