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 {ICustomer} from '../model/entities/customer';
import {IApiResponse} from '../model/virtual/api-response';
import {ICustomerContact} from '../model/entities/customer-contact';
import {IAppServiceData} from '../model/virtual/app-service-data';
import {isNull} from 'util';
import {ServiceHelper} from '../utils/service-helper';
import {ICustomerNote} from '../model/entities/customer-note';
import {ICustomerData} from '../model/virtual/customer-data';

@Injectable()
export class CustomerService {

    private customers: BehaviorSubject<ICustomer[]>;
    private dataCustomers$: Observable<ICustomer[]>;
    private customerContacts: BehaviorSubject<ICustomerContact[]>;
    private dataCustomerContacts$: Observable<ICustomerContact[]>;
    private serviceDataSub: Subscription;

    constructor(private httpService: HttpService, private cacheService: CacheService, private router: Router) {
        this.customers = new BehaviorSubject<ICustomer[]>(null);
        this.dataCustomers$ = this.customers.asObservable();
        this.customerContacts = new BehaviorSubject<ICustomerContact[]>(null);
        this.dataCustomerContacts$ = this.customerContacts.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 updatedCustomers: ICustomer[] = this.customers.getValue();
            let updatedCustomerContacts: ICustomerContact[] = this.customerContacts.getValue();
            if (!isNull(serviceData.customers)) {
                // Update service data
                updatedCustomers = ServiceHelper.updateServiceEntries(serviceData.customers, this.customers.getValue()) as ICustomer[];
                bSetNewData = true;
            }
            if (!isNull(serviceData.customerContacts)) {
                // Update service data
                updatedCustomerContacts = ServiceHelper.updateServiceEntries(serviceData.customerContacts, this.customerContacts.getValue()) as ICustomerContact[];
                bSetNewData = true;
            }
            if (bSetNewData) {
                this.setCustomerServiceData(updatedCustomers, updatedCustomerContacts);
            }
        }
    }

    /**
     * Sets customer service and cache data
     * @param customers
     * @param customerContacts
     */
    private setCustomerServiceData(customers: ICustomer[], customerContacts: ICustomerContact[]) {
        this.customers.next(customers);
        this.customerContacts.next(customerContacts);
    }

    /**
     * Reset service data (on logout)
     */
    public resetCustomerServiceData() {
        this.customers.next(null);
        this.customerContacts.next(null);
    }

    /**
     * Returns observable of customers
     * @returns {Observable<ICustomer[]>}
     */
    public getCustomers$(): Observable<ICustomer[]> {
        return this.dataCustomers$;
    }

    /**
     * Returns observable of customer contacts
     * @returns {Observable<ICustomer[]>}
     */
    public getCustomerContacts$(): Observable<ICustomerContact[]> {
        return this.dataCustomerContacts$;
    }



    /**
     * Gets all customers
     * @returns {Observable<IApiResponse>}
     */
    public apiGetCustomerData(): void {
        this.httpService.apiGet('get-customer-data').subscribe(
            data => {
                const res: ICustomerData = data.result_data as ICustomerData;
                this.setCustomerServiceData(res.customers, res.customerContacts);
            },
            error => {}
        );
    }

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

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

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

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

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

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

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

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

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

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