import { HttpErrorResponse } from "@angular/common/http";
import { AfterViewInit, Component, EventEmitter, Input, OnDestroy, Output, ViewChildren, ViewEncapsulation } from "@angular/core";
import { FormControl, FormGroup, Validators } from "@angular/forms";
import { ApiResources, UtilHelper } from "@shared/helpers";
import { OTPResponse, Page } from "@shared/models";
import { HttpService, NotifyService } from "@shared/services";
import { Subscription, interval } from "rxjs";
import { finalize, takeUntil } from "rxjs/operators";

class OTPModel {
    username: string;
    countryId: number;
    countryCode: string;
}

@Component({
    templateUrl: "./otp.html",
    selector: "otp",
    encapsulation: ViewEncapsulation.None
})
export class OTPWidget implements AfterViewInit, OnDestroy {
    @ViewChildren("formRow") rows: any;
    @Input() model: OTPModel;
    @Input() otp: string;
    @Input() otpExpiresIn: number;
    @Output() validateOTPEmitter = new EventEmitter<boolean>();

    page: Page;

    formInput = ["input1", "input2", "input3", "input4"];
    form: FormGroup;
    submitting: boolean;
    submitted: boolean;

    otpSession: Subscription;
    otpValid: boolean;

    constructor(
        private readonly httpService: HttpService,
        private readonly notifyService: NotifyService
    ) {
        this.page = new Page();
        this.startOTPSession();
        this.buildForm();
    }

    private buildForm() {
        this.form = this.toFormGroup(this.formInput);
    }

    private toFormGroup(elements) {
        const group: any = {};
        elements.forEach(key => {
            group[key] = new FormControl("", Validators.required);
        });
        return new FormGroup(group);
    }

    onKeyUpEvent(event, index: number) {
        const position = event.keyCode === 8 && event.which === 8 ? index - 1 : index + 1;
        if (position > -1 && position < this.formInput.length) {
            this.rows._results[position].nativeElement.focus();
        }
    }

    private startOTPSession() {
        this.otpSession = interval(1000).subscribe(() => {
            if (this.otpExpiresIn === 0) {
                this.endOTPSession();
                return;
            }

            this.otpExpiresIn--;
        });
    }

    private endOTPSession() {
        this.otpSession.unsubscribe();
        this.otpExpiresIn = undefined;
    }

    onSendOTP() {
        this.buildForm();

        this.submitting = true;
        this.httpService
            .post<OTPResponse>(ApiResources.getURI(ApiResources.application.base, ApiResources.application.sendOtp), this.model, false)
            .pipe(finalize(() => { this.submitted = false, this.submitting = false }))
            .pipe(takeUntil(this.page.unSubscribe))
            .subscribe(
                (response: OTPResponse) => {
                    if (response.error) {
                        this.notifyService.warning(response.errorDescription);
                    } else {
                        this.otp = response.otp;
                        this.otpExpiresIn = response.otpExpiresIn;
                        this.startOTPSession();
                    }
                },
                (error: HttpErrorResponse) => {
                    const errorMessage = UtilHelper.handleError(error);
                    if (errorMessage) {
                        this.notifyService.warning(errorMessage);
                    } else {
                        this.notifyService.defaultError();
                    }
                }
            );
    }

    onValidate() {
        this.submitted = true;
        if (!this.form.valid) {
            return;
        }

        const otp: string = this.rows._results.map(m => m.nativeElement.value).join("");
        if (this.otp === otp) {
            this.otpValid = true;
            this.validateOTPEmitter.emit(true);
        } else {
            this.otpValid = false;
        }
    }

    ngAfterViewInit() {
        this.rows._results[0].nativeElement.focus();
    }

    ngOnDestroy() {
        this.endOTPSession();
        this.page.unsubscribeAll();
    }
}