import { AfterViewInit, Component, ElementRef, OnInit, ViewChild } from '@angular/core';
import { RouterExtensions } from '@nativescript/angular';
import { ApplicationSettings } from '@nativescript/core';
import { Select, Store } from '@ngxs/store';
import { LoadFinishedEventData, WebViewExt } from '@nota/nativescript-webview-ext';
import { Feedback, FeedbackType } from 'nativescript-feedback';
import { Observable } from 'rxjs';
import { APP_ID, SERVER_URL, wsUserManagement } from '~/constants/api.constants';
import { USER_NAME, USER_ROLE, USER_ROLE_ID, USER_TOKEN, USER_UNIT_ID } from '~/constants/login-constants';
import { transitionOptions } from '~/constants/shared.constants';
import { UserRoleAll } from '~/core/entities/input/userRoleAll';
import { UserRoleAllOutput } from '~/core/entities/output/userRoleAllOutput';
import { WebApiService } from '~/core/services/web-api.service';
import {
    LoadUserDetail,
    StartSkautISLoading,
    StartSkautISPageLoading,
    StopSkautISLoading,
    StopSkautISPageLoading
} from '~/pages/login/state-mgmt/login.actions';
import { LoginState } from '~/pages/login/state-mgmt/login.state';

@Component({
    moduleId: module.id,
    selector: 'login-component',
    templateUrl: './login.component.html',
    styleUrls: ['./_login.component.scss']
})

export class LoginComponent implements OnInit, AfterViewInit {
    @Select(LoginState.isLoading) isLoading$: Observable<boolean>;
    @ViewChild('loginWebView', { static: true }) loginWebViewRef: ElementRef<WebViewExt>;

    feedback: Feedback;
    loginWebViewSrc: string = `${SERVER_URL}Login/?appid=${APP_ID}`;

    constructor(
        private routerExtensions: RouterExtensions,
        private store: Store,
        private webApiService: WebApiService,
    ) {
        this.feedback = new Feedback();
    }

    ngOnInit() {
        this.store.dispatch(new StartSkautISPageLoading());
    }

    /**
     * In hook I get webView ( I am using https://market.nativescript.org/plugins/@nota%2Fnativescript-webview-ext webview bacause of needed evaluate javascript
     * In LoadFinished event (page in src was loaded), I check if login page is loaded and If then I stop loading and too
     * I check if loaded url is https://test-is.skaut.cz/Login/LoggedIn.aspx what is
     * url, where is page redirect after successful send login form. In it I dispatch action for start loading,
     * then execute javascript for getting body content, then delete this content (because of hide data before user)
     * Then I call onUserLogged function with parsed body content which do rest of login process
     *
     */
    ngAfterViewInit() {
        const webView = this.loginWebViewRef && this.loginWebViewRef.nativeElement;
        webView.on('loadFinished', (args: LoadFinishedEventData) => {
            if (args.url === this.loginWebViewSrc) {
                this.store.dispatch(new StopSkautISPageLoading());
            }
            if (args.url === `${SERVER_URL}Login/LoggedIn.aspx`) {
                this.store.dispatch(new StartSkautISLoading());

                webView.executeJavaScript('document.body.outerText')
                    .then((body: string) => {
                        webView.executeJavaScript('document.body.outerText = \'\'')
                            .then((resp: string) => {
                                this.onUserLogged(this.parseBodyText(body));
                            });
                    });
            }
        });

    }

    /**
     * Split body by end of line, then by ':' where before : is kdy and after it is value (name, token...)
     * @param {string} body
     * @returns {any} Object with data from login response
     */
    parseBodyText(body: string): any {
        return body.split(/\r\n|\n|\r/).reduce((accum, currentVal) => {
            const items = currentVal.trim().split(': ');
            if (items.length === 2) {
                accum[items[0]] = items[1];
            }

            return accum;
        }, {});
    }

    /**
     * Check if loginItems are filled.
     * If are, then save data to AppSettings and dispatch action for load UserDetail and stopSkautIsLoading,
     * show feedback and navigate to /home otherwise
     *
     * @param loginItems
     */
    onUserLogged(loginItems: any) {
        if (
            loginItems.hasOwnProperty('UserName') &&
            loginItems.hasOwnProperty('skautIS Token') &&
            loginItems.hasOwnProperty('RoleID') &&
            loginItems.hasOwnProperty('UserID')
        ) {
            ApplicationSettings.setString(USER_NAME, loginItems['UserName']);
            ApplicationSettings.setString(USER_TOKEN, loginItems['skautIS Token']);
            ApplicationSettings.setNumber(USER_ROLE_ID, +loginItems['RoleID']);
            ApplicationSettings.setNumber(USER_UNIT_ID, +loginItems['UnitID']);
            const userRoleAll = new UserRoleAll(APP_ID, loginItems['skautIS Token'], loginItems['UserID']);
            this.webApiService.call(userRoleAll,
                () => new UserRoleAllOutput(),
                wsUserManagement)
                .toPromise().then((res: UserRoleAllOutput[]) => {
                    const role = res.find(r => r.ID === +loginItems['RoleID'])
                    ApplicationSettings.setString(USER_ROLE, role.DisplayName);
                })

            this.store.dispatch(new LoadUserDetail());
            this.store.dispatch(new StopSkautISLoading());
        } else {
            this.feedback.show({
                title: 'ERROR',
                type: FeedbackType.Error,
                message: 'Přihlášení se nepodařilo. Zkuste to později znovu.'
            });
            this.routerExtensions.navigate(['/home'], { clearHistory: true, transition: transitionOptions });
        }
    }

    onBackButton(): void {
        this.routerExtensions.back();
    }
}
