import { HttpErrorResponse } from "@angular/common/http";
import { Component, OnDestroy, OnInit, ViewEncapsulation } from "@angular/core";
import { FormBuilder, FormGroup, Validators } from "@angular/forms";
import { Router } from "@angular/router";
import { Setting } from "@shared/entities";
import { ApiResources, UtilHelper } from "@shared/helpers";
import { IResource, IUserAccount, Page } from "@shared/models";
import { AppConfig, AppData, HttpService, IdentityService, MenuService, NotifyService, ResourceService } from "@shared/services";
import { EmailValidator, MobileValidator } from "@shared/validators";
import { Subscription } from "rxjs";
import { debounceTime, finalize, takeUntil } from "rxjs/operators";

class LoginRequest {
    type: string;
    username: string;
    countryId: number;
    password: string;
    accountTypes: Array<number>;
    deviceId: string;
    deviceToken: string;
    deviceType: string;
    locationId: number;
}

@Component({
    templateUrl: "./login.html",
    encapsulation: ViewEncapsulation.None
})
export class LoginPage implements OnInit, OnDestroy {
    page: Page;

    loadingCountries: boolean;
    countries: Array<IResource>;
    locations: Array<IResource>;
    locationMap: Array<IResource>;
    loadingLocationMap: boolean;
    locationDropDown: boolean;

    env: string;
    envTitle: string;
    loginForm: FormGroup;
    submitting: boolean;
    submitted: boolean;
    logoBasics: Setting;
    logoSubscription: Subscription;
    loadingSettings: boolean;
    isTheme: boolean;
    themeColor: string;
    loading: boolean;

    constructor(
        private readonly httpService: HttpService,
        private readonly router: Router,
        private readonly formBuilder: FormBuilder,
        private readonly identityService: IdentityService,
        private readonly menuService: MenuService,
        private readonly resourceService: ResourceService,
        private readonly notifyService: NotifyService,
        private readonly appData: AppData
    ) {
        this.locations = new Array<IResource>();
        this.countries = new Array<IResource>();
        this.buildForm();
        this.env = AppConfig.settings.env.toLowerCase();
        this.envTitle = AppConfig.settings.envTitle;
        this.page = new Page();
        this.locationDropDown = false;
        this.logoBasics = new Setting();
    }

    getLogoImage = () => {
        this.loading = true;

        this.httpService
            .get<Array<Setting>>(ApiResources.getURI(ApiResources.setting.base, ApiResources.setting.fetch), { type: "Logo", active: true })
            .pipe(takeUntil(this.page.unSubscribe))
            .pipe(finalize(() => { this.loading = false }))
            .subscribe({
                next: (response: Array<Setting>) => {
                    if (response && response.length > 0) {
                        this.logoBasics = response[0];
                        if (UtilHelper.isEmpty(response[0].imageUrl)) {
                            response[0].imageUrl = `${ApiResources.getURI(ApiResources.resources.base, ApiResources.resources.getProfileImage)}?imagePath=${response[0].imageUrl}`;
                        }
                    }
                },
                error: () => {
                    this.logoBasics = new Setting();
                }
            });
    }

    private fetchCountries() {
        this.loadingCountries = true;
        this.resourceService.countries()
            .pipe(finalize(() => { this.loadingCountries = false }))
            .pipe(takeUntil(this.page.unSubscribe))
            .subscribe((response: Array<IResource>) => {
                this.countries = response;
                this.loginForm.get("countryId").patchValue(response[0].id);
            });
    }

    private fetchLocationMap(type: string, value: string) {
        this.loadingLocationMap = true;
        this.resourceService.locationAccountDynamic(type, value)
            .pipe(finalize(() => { this.loadingLocationMap = false }))
            .pipe(takeUntil(this.page.unSubscribe))
            .subscribe((response: Array<IResource>) => {
                this.setAccountLocation(response)
            });
    }

    private buildForm() {
        this.loginForm = this.formBuilder.group({
            type: [null],
            countryId: [null, [Validators.required]],
            locationId: [null, [Validators.required]],
            username: ["", [Validators.required]],
            password: ["", [Validators.required]]
        });
        this.loginForm.get("countryId").valueChanges.subscribe(() => {
            this.loginForm.get("username").updateValueAndValidity();
        });

        this.loginForm.get("username").valueChanges.pipe(debounceTime(300)).subscribe((username: string) => {
            const typeControl = this.loginForm.get("type");
            const usernameControl = this.loginForm.get("username");

            if (username) {
                let type = /^[0-9]+$/.test(username) ? "M" : "E";
                if (type === "M") {
                    usernameControl.setValidators([Validators.required, MobileValidator.isValid]);
                } else {
                    if (username.includes("@")) {
                        usernameControl.setValidators([Validators.required, EmailValidator.isValid]);
                    }
                    else {
                        usernameControl.setValidators([Validators.nullValidator])
                    }
                }
                typeControl.patchValue(type);
                if (type === "E") {
                    type = username.includes("@") ? "E" : "U";
                }
                this.fetchLocationMap(type, username);
            } else {
                this.locationDropDown = false;
                typeControl.patchValue(null);
                usernameControl.setValidators([Validators.required]);
            }
        });
    }

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

    onSubmit() {
        this.submitted = true;
        if (!this.loginForm.valid) {
            this.notifyService.warningToast("PLEASE ENTER VALID CREDENTIALS")
            return;
        }
        const model = UtilHelper.clone(this.loginForm.getRawValue()) as LoginRequest;
        model.username = model.type && model.type === "M" ? model.countryId + ":" + model.username : model.username;
        model.deviceType = "Web";
        model.deviceId = Math.random().toString(36).substring(2) + Date.now().toString(36);
        model.deviceToken = Math.random().toString(36).substring(2) + Date.now().toString(36);
        delete model.type;
        delete model.countryId;
        this.submitting = true;
        this.httpService
            .post<IUserAccount>(ApiResources.getURI(ApiResources.account.base, ApiResources.account.authenticate), model, false)
            .pipe(takeUntil(this.page.unSubscribe))
            .subscribe(
                (account: IUserAccount) => {
                    account.deviceId = model.deviceId;

                    this.identityService.signIn(account)
                        .pipe(takeUntil(this.page.unSubscribe))
                        .subscribe(() => {

                            this.menuService.fetch(account.accountId, account.roleId, () => {
                                this.appData.setAccount(account);
                                //this.appData.setPrint()
                                // this.router.navigate([this.menuService.getDefaultRoute]);
                                this.router.navigate(['app/accounts']);
                            });

                        }, () => {
                            this.submitting = false;
                            this.notifyService.defaultError();
                        });
                },
                (error: HttpErrorResponse) => {
                    this.submitting = false;
                    const errorMessage = UtilHelper.handleError(error);
                    if (errorMessage) {
                        this.notifyService.warningToast(errorMessage);
                    } else {
                        this.notifyService.defaultError();
                    }
                }
            );
    }

    setAccountLocation = (found: Array<IResource>) => {
        if (found && found.length) {
            this.loginForm.patchValue({
                locationId: found[0].id
            });
            this.locations = found;
            this.locationDropDown = found.length > 1;
        } else {
            this.locationDropDown = false;
        }
    }

    private getSettingsLayoutCommon() {
        this.loadingSettings = true;
        this.httpService.get<Array<Setting>>(ApiResources.getURI(ApiResources.setting.base, ApiResources.setting.fetch), { name: "Theme Color" })
            .pipe(takeUntil(this.page.unSubscribe))
            .pipe(finalize(() => this.loadingSettings = false))
            .subscribe((response: Array<Setting>) => {
                if (response.length > 0) {
                    this.isTheme = response[0].active;
                    this.themeColor = response[0].value;
                }
                this.onToggleTheme(this.themeColor);
            }), () => { this.onToggleTheme(this.themeColor); };
    }
    onToggleTheme(color: string) {
        switch (color) {
            case "#827d77 #fec32b #f5f6f9 #f86262":
                this.yellowTheme();
                break;
            default:
                this.blueTheme();
        }
    }

    yellowTheme() {
        const head = document.getElementsByTagName('head')[0];
        const fileref = document.createElement("link")
        fileref.setAttribute("rel", "stylesheet")
        fileref.setAttribute("type", "text/css")
        const fileName = location.origin + location.pathname + "assets/css/yellow-theme.css";
        fileref.setAttribute("href", fileName);
        fileref.media = 'all';
        head.appendChild(fileref);
    }

    blueTheme() {
        const head = document.getElementsByTagName('head')[0];
        const fileref = document.createElement("link")
        fileref.setAttribute("rel", "stylesheet")
        fileref.setAttribute("type", "text/css")
        const fileName = location.origin + location.pathname + "assets/css/blue-theme.css";
        fileref.setAttribute("href", fileName);
        fileref.media = 'all';
        head.appendChild(fileref);
    }

    ngOnInit() {
        this.getSettingsLayoutCommon();
        this.getLogoImage();

        $("body").addClass("auth-fluid-pages pb-0");
        this.locationDropDown = false;
        this.fetchCountries();
    }

    ngOnDestroy() {
        $("body").removeClass("auth-fluid-pages pb-0");
        this.page.unsubscribeAll();
    }
}