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, IFile } from '@red/domain';
import { mapEach } from '@common-ui/utils';

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

    #componentLogRequest(
        dossierTemplateId: string,
        dossierId: string,
        fileId: string,
        includeDetails = true,
    ): Observable<IComponentLogData> {
        return this._http.get<IComponentLogData>(
            `/api/dossier-templates/${dossierTemplateId}/dossiers/${dossierId}/files/${fileId}/components`,
            {
                params: { includeDetails },
            },
        );
    }

    #bulkComponentLogRequest(dossierTemplateId: string, dossierId: string, includeDetails = false): Observable<IComponentLogData> {
        return this._http.get<IComponentLogData>(
            `/api/dossier-templates/${dossierTemplateId}/dossiers/${dossierId}/files/bulk/get-components`,
            {
                params: { includeDetails },
            },
        );
    }

    getComponentLogData(dossierTemplateId: string, dossierId: string, fileId: string): Observable<ComponentLogEntry[]> {
        return this.#componentLogRequest(dossierTemplateId, dossierId, fileId).pipe(
            map(data => data.componentDetails),
            catchError(() => of({} as ComponentDetails)),
            map(componentDetails => this.#mapComponentDetails(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, file?: IFile): Observable<IComponentLogData> {
        const request$ = file?.fileId
            ? this.#componentLogRequest(dossierTemplateId, dossierId, file?.fileId, false)
            : this.#bulkComponentLogRequest(dossierTemplateId, dossierId);
        return request$.pipe(
            tap(data => {
                const blob = new Blob([JSON.stringify(data, null, 2)], { type: 'application/json' });
                saveAs(blob, (file?.filename ? `${file.filename}}.` : '') + 'component_log.json');
            }),
        );
    }

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

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

        const pathSuffix = file?.fileId ? `${file.fileId}/components` : 'bulk/get-components';

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

    #mapComponentDetails(componentDetails: ComponentDetails): IComponentLogEntry[] {
        return Object.keys(componentDetails).reduce((res, key) => (res.push(componentDetails[key]), res), []);
    }
}
