import { Component, OnDestroy, OnInit, TemplateRef, ViewEncapsulation } from "@angular/core";
import { takeUntil, finalize } from "rxjs/operators";
import { NgbModal, NgbModalRef } from "@ng-bootstrap/ng-bootstrap";

import { IUserAccount, Page, GenericResponse, GenericStatus, Pagination } from "@shared/models";
import { AppData, HttpService, NotifyService } from "@shared/services";
import { ApiResources, UtilHelper, LinqHelper } from "../../../../../shared/helpers";

import { FormGroup, FormBuilder, Validators } from "@angular/forms";
import { Subscription } from "rxjs";
import { IChargeModel } from "./models/charge.model";
import { RepeatType } from "../../../services/models/repeat-type.model";
import { IFilterModel } from "./models/filter.model";
import { AutomaticType } from "../../../services/models/automatic-type.model";
import { ChargeType } from "../../../../../shared/enums";
import { WhiteSpaceValidator } from "../../../../../shared/validators";
import { ModuleMaster } from "../../../../../shared/entities";


@Component({
    templateUrl: "./charge-management.html",
    encapsulation: ViewEncapsulation.None,
    styleUrls: ['./charge-management.css']
})
export class ChargeManagementPage implements OnInit, OnDestroy {
    page: Page;
    repeatType = RepeatType;
    automaticType = AutomaticType;
    chargeType = ChargeType;

    loading: boolean;
    selectedRecord: IChargeModel;
    records: Array<IChargeModel>;

    submitting: boolean;
    submitted: boolean;


    departments: Array<IFilterModel>;
    chargeGroups: Array<IFilterModel>;
    charges: Array<IFilterModel>;


    departmentsOriginal: Array<IFilterModel>;
    chargeGroupsOriginal: Array<IFilterModel>;
    chargesOriginal: Array<IFilterModel>;

    chargeFilterForm: FormGroup;
    mainForm: FormGroup;

    modalRef: NgbModalRef;

    pagination: Pagination;

    departmentSubscription: Subscription;
    chargeGroupSubscription: Subscription;
    chargeSubscription: Subscription;
    servicesmodules: Array<ModuleMaster>;
    servicesmodulesMasterId: number=0;

    constructor(
        private readonly httpService: HttpService,
        private readonly appData: AppData,
        private readonly modalService: NgbModal,
        private readonly formBuilder: FormBuilder,
        private readonly notifyService: NotifyService

    ) {
        this.initPagination();

        this.departments = new Array<IFilterModel>();
        this.chargeGroups = new Array<IFilterModel>();
        this.charges = new Array<IFilterModel>();


        this.departmentsOriginal = new Array<IFilterModel>();
        this.chargeGroupsOriginal = new Array<IFilterModel>();
        this.chargesOriginal = new Array<IFilterModel>();

        this.loading = true;
        this.page = new Page();
        this.servicesmodules = new Array<ModuleMaster>();
        this.buildFilterForm();
        this.buildMainForm();
    }

    ngOnInit() {
        this.appData.userAccount
            .pipe(takeUntil(this.page.unSubscribe))
            .subscribe((userAccount: IUserAccount) => {
                if (userAccount) {
                    this.page.userAccount = userAccount;
                    this.findServicesModuleMasterId();
                    this.fetchMasters(() => {
                        this.fetch();
                    });
                } else {
                    this.page.userAccount = undefined;
                }
            });
    }

    ngOnDestroy() {
        this.page.unsubscribeAll();
        this.page.unSubscribe.complete();
        this.departmentSubscription.unsubscribe();
        this.chargeGroupSubscription.unsubscribe();
        this.chargeSubscription.unsubscribe();
        this.servicesmodules = null;
    }

    private initPagination() {
        this.pagination = new Pagination();
        this.pagination.pageIndex = 1;
        this.pagination.pageSize = 10;
    }

    private buildFilterForm() {
        this.chargeFilterForm = this.formBuilder.group({
            department: [null],
            chargeGroup: [null],
            charge: [null]
        });

        this.departmentSubscription = this.chargeFilterForm.get("department").valueChanges.subscribe((value: string | null) => {
            this.onFilterDepartment(value);
        });

        this.chargeGroupSubscription = this.chargeFilterForm.get("chargeGroup").valueChanges.subscribe((value: string | null) => {
            this.onFilterChargeGroup(value);
        });

        this.chargeSubscription = this.chargeFilterForm.get("charge").valueChanges.subscribe((value: string | null) => {
            this.onFilterCharge(value);
        });
    }

    get form() { return this.mainForm.controls; };

    private buildMainForm() {
        this.mainForm = this.formBuilder.group({
            department: [null, [Validators.required, WhiteSpaceValidator.isValid]],
            chargeGroup: [null, [Validators.required, WhiteSpaceValidator.isValid]],
            charge: [null, [Validators.required, WhiteSpaceValidator.isValid]],
            repeatTypeId: [null, [Validators.required]],
            //modulesMasterId: [null,[Validators.required]]
            //cost: [null, [Validators.required]],
            //opCost: [null]
        });
    }

    onOpenModel(content: TemplateRef<any>, record?: IChargeModel) {
        this.resetAutocomplete();
        if (record) {
            this.selectedRecord = record;
            this.mainForm.patchValue({
                department: record.departmentName,
                chargeGroup: record.chargeGroupName,
                charge: record.chargeName,
                repeatTypeId: record.repeatTypeId,
                //modulesMasterId: this.servicesmodulesMasterId.modulesMasterId
                //cost: record.cost,
                //opCost: record.opCost || 0
            });
        } else {
            this.mainForm.reset();
            this.selectedRecord = null;
        }

        this.modalRef = this.modalService.open(content, {
            backdrop: "static",
            keyboard: false,
            centered: true,
            /*size: "lg",*/
            size:"modal-sm",
            windowClass: "custom-modal slots-modal effect-scale"
        });

        return;
    }

    onCloseModal() {
        try {
            this.modalRef.close();
            this.modalRef = undefined;
        } catch (e) {
            // ignored;
        }

        this.submitting = undefined;
        this.submitted = undefined;
        this.selectedRecord = null;
        this.resetAutocomplete();
    }

    clearChargeFilter = () => {
        this.chargeFilterForm.patchValue({
            department: null,
            chargeGroup: null,
            charge: null,
        });
        this.initPagination();
        this.fetch();
        this.resetAutocomplete();

    }

    resetAutocomplete = () => {
        this.departments = LinqHelper.cloneDeepArray<IFilterModel>(this.departmentsOriginal.filter(LinqHelper.uniqueOnlyBy));
        this.chargeGroups = LinqHelper.cloneDeepArray<IFilterModel>(this.chargeGroupsOriginal.filter(LinqHelper.uniqueOnlyBy));
        this.charges = LinqHelper.cloneDeepArray<IFilterModel>(this.chargesOriginal.filter(LinqHelper.uniqueOnlyBy));
    }

    chargeFilter = () => {
        this.initPagination();
        this.fetch();
    }

    onNextPage() {
        this.fetch();
    }

    fetch = () => {
        const data = {
            ...this.chargeFilterForm.value,
            pageIndex: this.pagination.pageIndex,
            pageSize: this.pagination.pageSize
        }
        this.httpService
            .post<GenericResponse>(ApiResources.getURI(ApiResources.chargeManagement.base, ApiResources.chargeManagement.fetch), data)
            .pipe(takeUntil(this.page.unSubscribe))
            .pipe(finalize(() => this.loading = false))
            .subscribe(
                (response: GenericResponse) => {
                    const data = response.data as Array<IChargeModel>;
                    this.records = data;
                    UtilHelper.applyPagination(this.records, this.pagination);
                },
                () => {
                    this.records = new Array<IChargeModel>();
                }
            );
    }

    fetchMasters = (callback?: Function) => {
        this.httpService
            .post<GenericResponse>(ApiResources.getURI(ApiResources.chargeManagement.base, ApiResources.chargeManagement.masters), {})
            .pipe(takeUntil(this.page.unSubscribe))
            .pipe(finalize(() => this.loading = false))
            .subscribe(
                (response: GenericResponse) => {
                    const data = response.data as Array<IChargeModel>;
                    this.departmentsOriginal = data.map((x) => ({ chargeGroupName: x.chargeGroupName, chargeName: x.chargeName, id: x.departmentId, name: x.departmentName })) as Array<IFilterModel>;
                    this.departments = LinqHelper.cloneDeepArray<IFilterModel>(this.departmentsOriginal.filter(LinqHelper.uniqueOnlyBy));

                    this.chargeGroupsOriginal = data.map((x) => ({ departmentId: x.departmentId, departmentName: x.departmentName, chargeName: x.chargeName, id: x.chargeGroupId, name: x.chargeGroupName })) as Array<IFilterModel>;
                    this.chargeGroups = LinqHelper.cloneDeepArray<IFilterModel>(this.chargeGroupsOriginal.filter(LinqHelper.uniqueOnlyBy));

                    this.chargesOriginal = data.map((x) => ({ departmentName: x.departmentName, chargeGroupId: x.chargeGroupId, chargeGroupName: x.chargeGroupName, id: x.chargeId, name: x.chargeName })) as Array<IFilterModel>;
                    this.charges = LinqHelper.cloneDeepArray<IFilterModel>(this.chargesOriginal.filter(LinqHelper.uniqueOnlyBy));

                    callback();
                },
                () => {
                    callback();
                }
            );
    }

    onSubmit = () => {
        this.submitted = true;
        if (this.mainForm.invalid) return;
        //const moduleMasterId = this.servicesmodulesMasterId;
        const moduleMasterId = this.servicesmodules[0].modulesMasterId;
        this.submitting = true;
        var department = this.departmentsOriginal.find(x => x.name === this.mainForm.value.department);
        var chargeGroup = department
            ? this.chargeGroupsOriginal.find(x => x.departmentId === department.id && x.name === this.mainForm.value.chargeGroup)
            : null;

        var data = {
            departmentId: department ? department.id : 0,
            departmentName: this.mainForm.value.department,
            chargeGroupId: chargeGroup ? chargeGroup.id : 0,
            chargeGroupName: this.mainForm.value.chargeGroup,
            chargeName: this.mainForm.value.charge,
            modulesMasterId: moduleMasterId,
            //cost: this.mainForm.value.cost,
            //opCost: this.mainForm.value.opCost,
            repeatTypeId: this.mainForm.value.repeatTypeId,
            createdBy: this.page.userAccount.accountId,
            modifiedByName: this.page.userAccount.fullName
        }

        if (this.selectedRecord) {
            data["chargeId"] = this.selectedRecord.chargeId;
            data["oldChargeGroupId"] = this.selectedRecord.chargeGroupId;
        }

        const subUrl = this.selectedRecord
            ? ApiResources.chargeManagement.update
            : ApiResources.chargeManagement.insert;

        this.httpService
            .post<GenericResponse>(ApiResources.getURI(ApiResources.chargeManagement.base, subUrl), data)
            .pipe(takeUntil(this.page.unSubscribe))
            .pipe(finalize(() => this.submitting = false))
            .subscribe(
                (response: GenericResponse) => {
                    if (response.status === GenericStatus[GenericStatus.Success]) {
                        this.onCloseModal();
                        this.clearChargeFilter();
                        this.notifyService.info(`Charge has been ${data["chargeId"] ? 'Updated' : 'Added'} successfully`,
                            () => {
                                this.selectedRecord = null;
                                this.fetchMasters(() => {
                                    this.fetch();
                                });
                            });
                    }

                    if (response.status === GenericStatus[GenericStatus.Error]) {
                        this.notifyService.defaultError();
                    }

                    if (response.status === GenericStatus[GenericStatus.Info]) {
                        this.notifyService.warning("Charge is already exists, please enter different charge and try again");
                    }
                },
                () => {
                    this.notifyService.defaultError();
                }
            );
    }

    onFilterDepartment = (record: string) => {
        this.chargeGroups = LinqHelper.cloneDeepArray<IFilterModel>(this.chargeGroupsOriginal.filter(x => !record ? true : x.departmentName.indexOf(record) !== -1).filter(LinqHelper.uniqueOnlyBy));
        this.charges = LinqHelper.cloneDeepArray<IFilterModel>(this.chargesOriginal.filter(x => !record ? true : x.departmentName.indexOf(record) !== -1).filter(LinqHelper.uniqueOnlyBy));
    }

    onFilterChargeGroup = (record: string) => {
        this.charges = LinqHelper.cloneDeepArray<IFilterModel>(this.chargesOriginal.filter(x => !record ? true : x.chargeGroupName.indexOf(record) !== -1).filter(LinqHelper.uniqueOnlyBy));
        this.departments = LinqHelper.cloneDeepArray<IFilterModel>(this.departmentsOriginal.filter(x => !record ? true : x.chargeGroupName.indexOf(record) !== -1).filter(LinqHelper.uniqueOnlyBy));
    }

    onFilterCharge = (record: string) => {
        this.chargeGroups = LinqHelper.cloneDeepArray<IFilterModel>(this.chargeGroupsOriginal.filter(x => !record ? true : x.chargeName.indexOf(record) !== -1).filter(LinqHelper.uniqueOnlyBy));
        this.departments = LinqHelper.cloneDeepArray<IFilterModel>(this.departmentsOriginal.filter(x => !record ? true : x.chargeName.indexOf(record) !== -1).filter(LinqHelper.uniqueOnlyBy));
    }

    private findServicesModuleMasterId() {
        this.loading = true;
        const request = {
            moduleName: "Services"
        };
        this.httpService.post(ApiResources.getURI(ApiResources.modulesMaster.base, ApiResources.modulesMaster.fetch), request)
            .pipe(takeUntil(this.page.unSubscribe))
            .pipe(finalize(() => this.loading = false))
            .subscribe((response: Array<ModuleMaster>) => {
                this.servicesmodules = response;
            });
    }
}