import {Component, OnDestroy, OnInit} from '@angular/core';
import {FormControl, FormGroup, Validators} from "@angular/forms";
import {ActivatedRoute} from "@angular/router";
import {filter, map, Observable, take, tap, zip} from "rxjs";
import {select, Store} from "@ngrx/store";
import {
    fromAuthorize,
    selectApplicationRegisteredFlag,
    selectAuthorizingUserFlag,
    selectCurrentInstanceWithApplicationRegisteredState,
    selectDataForAuthorizationFlow,
    selectIsLoggedIn,
    selectRegisteringApplicationFlag
} from "../../shared/state/store";

@Component({
    selector: 'app-authorize',
    templateUrl: './authorize.component.html',
    styleUrls: ['./authorize.component.scss']
})
export class AuthorizeComponent implements OnInit, OnDestroy {
    steps = [
        {label: 'Register Instance', description: 'Register the instance with the application', isValid: false},
        {label: 'Authorize User', description: 'Authorize User with instance', isValid: false},
    ];
    registeringApplication$: Observable<boolean>;
    applicationRegistered$: Observable<boolean>;
    authorizingUser$: Observable<boolean>;
    loggedIn$: Observable<boolean>;
    instanceName$: Observable<string | undefined>;
    serverForm = new FormGroup({
        instance: new FormControl('', [Validators.required]),
    });

    constructor(private store: Store, private route: ActivatedRoute) {
        this.registeringApplication$ = this.store.pipe(select(selectRegisteringApplicationFlag));
        this.applicationRegistered$ = this.store.pipe(select(selectApplicationRegisteredFlag));
        this.authorizingUser$ = this.store.pipe(select(selectAuthorizingUserFlag));
        this.loggedIn$ = this.store.pipe(select(selectIsLoggedIn));
        this.instanceName$ = this.store.pipe(
            select(selectCurrentInstanceWithApplicationRegisteredState),
            tap((result) => {
                if (result.instanceName !== undefined && result.applicationRegistered) {
                    this.serverForm.get('instance')?.setValue(result.instanceName);
                    this.serverForm.get('instance')?.disable();
                } else {
                    this.serverForm.get('instance')?.enable();
                }
            }),
            map((result) => result.instanceName)
        );
        zip(
            this.route.queryParams,
            this.instanceName$,
            this.loggedIn$,
        )
            .pipe(
                filter(([params, instanceName, isLoggedIn]) => params['code'] && instanceName !== undefined && !isLoggedIn),
                take(1),
            ).subscribe(([params]) => {
                this.store.pipe(
                    select(selectDataForAuthorizationFlow),
                    take(1),
                ).subscribe((data) => {
                    this.store.dispatch(fromAuthorize.getAccessToken({
                        code: params['code'],
                        instanceName: data.instanceName!,
                        clientId: data.clientId!,
                        clientSecret: data.clientSecret!,
                        redirectUrl: data.redirectUrl!,
                    }));
                });
            }
        );
    }


    ngOnInit(): void {
    }

    async registerApplication() {
        const instanceName = this.serverForm.get('instance')?.value;
        if (instanceName) {
            const redirectUrl = window.location.protocol + '//' + window.location.host + window.location.pathname;
            this.store.dispatch(fromAuthorize.registerApplication({instanceName, redirectUrl}));
        }
    }

    ngOnDestroy(): void {
    }

    authorizeUser() {
        this.store.pipe(
            select(selectDataForAuthorizationFlow),
            take(1),
        ).subscribe((data) => {
            this.store.dispatch(fromAuthorize.authorizeUser({
                instanceName: data.instanceName!,
                clientId: data.clientId!,
                redirectUrl: data.redirectUrl!,
            }));
        });
    }

    logout() {
        this.store.dispatch(fromAuthorize.logout());
    }
}
