import { Injectable } from '@angular/core';
import { GenericService } from '@iqser/common-ui';
import { catchError, map, tap } from 'rxjs/operators';
import { Observable, of } from 'rxjs';
import { HttpHeaders } from '@angular/common/http';
import { saveAs } from 'file-saver';
import { ComponentDetails, ComponentLogEntry, IComponentLogData, IComponentLogEntry } from '@red/domain';
import { mapEach } from '@common-ui/utils';

@Injectable({ providedIn: 'root' })
export class ComponentLogService extends GenericService<void> {
    protected readonly _defaultModelPath = '';

    getComponentLogData(dossierTemplateId: string, dossierId: string, fileId: string): Observable<ComponentLogEntry[]> {
        return this._http
            .get<IComponentLogData>(`/api/dossier-templates/${dossierTemplateId}/dossiers/${dossierId}/files/${fileId}/components`, {
                params: { includeDetails: true },
            })
            .pipe(
                map(data => data.componentDetails),
                catchError(() => of({} as ComponentDetails)),
                map(componentDetails => this.#filterComponentDetails(componentDetails)),
                mapEach(log => new ComponentLogEntry(log)),
            );
    }

    override(dossierId: string, fileId: string, componentOverrides: Record<string, string>): Observable<void> {
        return this._post({ componentOverrides }, `componentLog/override/${dossierId}/${fileId}`);
    }

    revertOverride(dossierId: string, fileId: string, components: string[]): Observable<void> {
        return this._post({ components }, `componentLog/override/revert/${dossierId}/${fileId}`);
    }

    exportJSON(dossierTemplateId: string, dossierId: string, fileId: string, name: string): Observable<ComponentLogEntry[]> {
        return this.getComponentLogData(dossierTemplateId, dossierId, fileId).pipe(
            tap(data => {
                const blob = new Blob([JSON.stringify(data, null, 2)], { type: 'application/json' });
                saveAs(blob, name + '.component_log.json');
            }),
        );
    }

    exportXML(dossierTemplateId, dossierId: string, fileId: string, name: string): Observable<string> {
        return this.#getComponentLogDataAsXML(dossierTemplateId, dossierId, fileId).pipe(
            tap(data => {
                const blob = new Blob([data], { type: 'application/xml' });
                saveAs(blob, name + '.component_log.xml');
            }),
        );
    }

    #getComponentLogDataAsXML(dossierTemplateId: string, dossierId: string, fileId: string) {
        let headers = new HttpHeaders();
        headers = headers.set('accept', 'application/xml');

        return this._http.get(`/api/dossier-templates/${dossierTemplateId}/dossiers/${dossierId}/files/${fileId}/components`, {
            headers: headers,
            responseType: 'text',
            observe: 'body',
        });
    }

    #filterComponentDetails(componentDetails: ComponentDetails): IComponentLogEntry[] {
        return Object.keys(componentDetails)
            .filter(function (key) {
                const component = componentDetails[key];
                return !!component.componentValues[0].entityReferences.length;
            })
            .reduce((res, key) => (res.push(componentDetails[key]), res), []);
    }
}
