import {Injectable} from '@angular/core';
import {BehaviorSubject, Observable, Subscription} from 'rxjs';
import {CacheService} from './cache.service';
import {Router} from '@angular/router';
import {HttpService} from './http.service';
import {IApiResponse} from '../model/virtual/api-response';
import {IAppServiceData} from '../model/virtual/app-service-data';
import {isNull} from 'util';
import {ServiceHelper} from '../utils/service-helper';
import {saveAs} from 'file-saver';
import {IService} from '../model/entities/service';
import {IServiceContact} from '../model/entities/service-contact';
import {IServiceData} from '../model/virtual/service-data';
import {IServiceNote} from '../model/entities/service-note';

@Injectable()
export class ServiceService {

    private services: BehaviorSubject<IService[]>;
    private dataServices$: Observable<IService[]>;
    private serviceContacts: BehaviorSubject<IServiceContact[]>;
    private dataServiceContacts$: Observable<IServiceContact[]>;
    private serviceDataSub: Subscription;

    constructor(private httpService: HttpService, private cacheService: CacheService, private router: Router) {
        this.services = new BehaviorSubject<IService[]>(null);
        this.dataServices$ = this.services.asObservable();
        this.serviceContacts = new BehaviorSubject<IServiceContact[]>(null);
        this.dataServiceContacts$ = this.serviceContacts.asObservable();

        // Subscription for service data
        this.serviceDataSub = this.httpService.getServiceData$().subscribe(
            data => {
                this.handleServiceData(data as IAppServiceData);
            }, error => {
            }
        );
    }

    /**
     * Handles service data updates
     * @param {IAppServiceData} serviceData
     */
    public handleServiceData(serviceData: IAppServiceData = null): void {
        if (!isNull(serviceData)) {
            let bSetNewData = false;
            let updatedServices: IService[] = this.services.getValue();
            let updatedServiceContacts: IServiceContact[] = this.serviceContacts.getValue();
            if (!isNull(serviceData.services)) {
                // Update service data
                updatedServices = ServiceHelper.updateServiceEntries(serviceData.services, this.services.getValue()) as IService[];
                bSetNewData = true;
            }
            if (!isNull(serviceData.serviceContacts)) {
                // Update service data
                updatedServiceContacts = ServiceHelper.updateServiceEntries(serviceData.serviceContacts, this.serviceContacts.getValue()) as IServiceContact[];
                bSetNewData = true;
            }
            if (bSetNewData) {
                this.setServiceServiceData(updatedServices, updatedServiceContacts);
            }
        }
    }

    /**
     * Sets service service and cache data
     * @param services
     * @param serviceContacts
     */
    private setServiceServiceData(services: IService[], serviceContacts: IServiceContact[]) {
        this.services.next(services);
        this.serviceContacts.next(serviceContacts);
    }

    /**
     * Reset service data (on logout)
     */
    public resetServiceServiceData() {
        this.services.next(null);
        this.serviceContacts.next(null);
    }

    /**
     * Returns observable of services
     * @returns {Observable<IService[]>}
     */
    public getServices$(): Observable<IService[]> {
        return this.dataServices$;
    }

    /**
     * Returns observable of service contacts
     * @returns {Observable<IService[]>}
     */
    public getServiceContacts$(): Observable<IServiceContact[]> {
        return this.dataServiceContacts$;
    }

    /**
     * Gets all services
     * @returns {Observable<IApiResponse>}
     */
    public apiGetServiceData(): void {
        this.httpService.apiGet('get-service-data').subscribe(
            data => {
                const res: IServiceData = data.result_data as IServiceData;
                this.setServiceServiceData(res.services, res.serviceContacts);
            },
            error => {}
        );
    }

    /**
     * Returns full service
     * @param {number} serviceId
     * @returns {Observable<IApiResponse>}
     */
    public apiGetServiceFull(serviceId: number): Observable<IApiResponse> {
        const formData = new FormData();
        formData.append('serviceId', JSON.stringify(serviceId));
        return this.httpService.apiPost('get-service-full', formData);
    }

    /**
     * Create service
     * @param {IService} service
     * @returns {Observable<IApiResponse>}
     */
    public apiCreateService(service: IService): Observable<IApiResponse> {
        const formData = new FormData();
        formData.append('service', JSON.stringify(service));
        return this.httpService.apiPost('create-service', formData);
    }

    /**
     * Edit service
     * @param {IService} service
     * @returns {Observable<IApiResponse>}
     */
    public apiEditService(service: IService): Observable<IApiResponse> {
        const formData = new FormData();
        formData.append('service', JSON.stringify(service));
        return this.httpService.apiPost('edit-service', formData);
    }

    /**
     * Create service contact
     * @param serviceContact
     */
    public apiCreateServiceContact(serviceContact: IServiceContact): Observable<IApiResponse> {
        const formData = new FormData();
        formData.append('serviceContact', JSON.stringify(serviceContact));
        return this.httpService.apiPost('create-service-contact', formData);
    }

    /**
     * Edit service contact
     * @param {IServiceContact} serviceContact
     * @returns {Observable<IApiResponse>}
     */
    public apiEditServiceContact(serviceContact: IServiceContact): Observable<IApiResponse> {
        const formData = new FormData();
        formData.append('serviceContact', JSON.stringify(serviceContact));
        return this.httpService.apiPost('edit-service-contact', formData);
    }

    /**
     * Delete service contact
     * @param {number} serviceContactId
     * @returns {Observable<IApiResponse>}
     */
    public apiDeleteServiceContact(serviceContactId: number): Observable<IApiResponse> {
        const formData = new FormData();
        formData.append('serviceContactId', JSON.stringify(serviceContactId));
        return this.httpService.apiPost('delete-service-contact', formData);
    }

    /**
     * Create service note
     * @param {IServiceNote} serviceNote
     * @returns {Observable<IApiResponse>}
     */
    public apiCreateServiceNote(serviceNote: IServiceNote): Observable<IApiResponse> {
        const formData = new FormData();
        formData.append('serviceNote', JSON.stringify(serviceNote));
        return this.httpService.apiPost('create-service-note', formData);
    }

    /**
     * Edit service note
     * @param {IServiceNote} serviceNote
     * @returns {Observable<IApiResponse>}
     */
    public apiEditServiceNote(serviceNote: IServiceNote): Observable<IApiResponse> {
        const formData = new FormData();
        formData.append('serviceNote', JSON.stringify(serviceNote));
        return this.httpService.apiPost('edit-service-note', formData);
    }

    /**
     * Delete service note
     * @param {number} serviceNoteId
     * @returns {Observable<IApiResponse>}
     */
    public apiDeleteServiceNote(serviceNoteId: number): Observable<IApiResponse> {
        const formData = new FormData();
        formData.append('serviceNoteId', JSON.stringify(serviceNoteId));
        return this.httpService.apiPost('delete-service-note', formData);
    }

    /**
     * Edit service meeting report
     * @param serviceMeetingId
     * @param serviceMeetingReport
     */
    public apiEditServiceMeetingReport(serviceMeetingId: number, serviceMeetingReport: string): Observable<IApiResponse> {
        const formData = new FormData();
        formData.append('serviceMeetingId', JSON.stringify(serviceMeetingId));
        formData.append('serviceMeetingReport', JSON.stringify(serviceMeetingReport));
        return this.httpService.apiPost('edit-service-meeting-report', formData);
    }

    /**
     * Returns meeting list as excel
     * @param meetingList
     * @param fileName
     */
    public apiExportXmasPdf(meetingList: {}[], fileName: string): void {
        const formData = new FormData();
        formData.append('meetingList', JSON.stringify(meetingList));
        this.httpService.apiFilePost('export-meeting-list', formData).subscribe(
            data => {
                saveAs(new Blob([data], {type: 'pdf'}), fileName + '.pdf');
            },
            error => {
            }
        );
    }
}
