import { HttpClient } from '@angular/common/http';
import { Injectable, NgZone } from '@angular/core';
import { RouterExtensions } from '@nativescript/angular';
import { parse, XElement } from 'nativescript-xmlobjects';
import { BaseInput } from '~/core/entities/input/baseInput';
import { BaseOutput } from '~/core/entities/output/baseOutput';
import { LoginDataService } from '~/core/services/login-data.service';
import { WebApiService } from '~/core/services/web-api.service';

/**
 * WebApiUnitMembersService extends WebApiService
 * Services that takes care of communication with the skautIs web services.
 * Unlike  WebApiService this class specify parsing response specific for UnitMembers
 * where response is consisting of more data which are parsing to separate entity
 *
 */
@Injectable()
export class WebApiUnitMembersService extends WebApiService {
    constructor(
        httpClient: HttpClient,
        loginDataSrv: LoginDataService,
        routerExtensions: RouterExtensions,
        zone: NgZone,
    ) {
        super(httpClient, loginDataSrv, routerExtensions, zone);
    }

    /**
     * Function parse xml response to result entity create by $outputEntityCreator
     * @param response
     * @param entity
     * @param entityName
     * @param outputEntityCreator
     * @returns {any}
     */
    protected parseResponse(response: string, entity: BaseInput, entityName: string, outputEntityCreator: () => BaseOutput): BaseOutput {
        const doc = parse(response);
        const elementRes: XElement = doc.root
            .element('soap:Body')
            .element(`${entityName}Response`);

        let resultElement: XElement;

        if (elementRes.element(`${entityName}Result`)) {
            resultElement = elementRes.element(`${entityName}Result`);
        }

        if (resultElement) {
            const outputEntity = outputEntityCreator();

            resultElement.nodes().forEach((element: XElement) => {
                if (element.nodes().length > 0 && outputEntity.hasOwnProperty(element.name.toString())) {
                    outputEntity[element.name.toString()] = this.parentEleToType(element, outputEntity, entityName);
                }
            });

            return outputEntity;
        } else {
            throw Error('While retrieve statistics of registration occur error.');
        }
    }

    /**
     * Convert element to entity type and call eleToType function to fill attribute of $outputEntity
     * It use function define in handler of output entity for creating new output entity for subtypentity.
     * OutputEntity has to define this creating function
     *
     * @param {XElement} element
     * @param outputEntity
     * @param entityName
     * @returns {BaseOutput|any}
     */
    protected parentEleToType(element: XElement, outputEntity: BaseOutput | any, entityName: string): BaseOutput[] {
        const elements: XElement[] = element
            .elements(`${entityName}${element.name.toString().replace('Members', '')}`); // name of element like UnitRegistrationMembersAge, if there will be twice Members remove it once

        return elements
            .filter((ele: XElement) => ele.nodes().length > 0)
            .map((ele: XElement) => this.eleToType(ele, outputEntity.handler[`getNew${entityName.toString()}${element.name.toString().replace('Members', '')}Output`]())); // name of element like UnitRegistrationMembersAge, if there will be twice Members remove it once
    }
}
