import {Injectable} from "@angular/core";
import {Actions, createEffect, ofType} from "@ngrx/effects";
import {fromAuthorize} from "../actions";
import {catchError, exhaustMap, map, of, switchMap, tap, throwError} from "rxjs";
import {NbToastrService} from "@nebular/theme";
import {MastodonApiAuthenticationService, RegisteredApp} from "projects/mastodon-api/src/public-api";
import {Store} from "@ngrx/store";
import {environment} from "../../../../../environments/environment";

@Injectable()
export class AuthorizationStateEffects {
    registerApplication$ = createEffect(() =>
        this.actions$.pipe(
            ofType(fromAuthorize.registerApplication),
            exhaustMap((action) =>
                this.mastodonApiAuthService
                    .createApp(action.instanceName, environment.appName, action.redirectUrl, environment.appWebsite)
                    .pipe(
                        map((registeredApp: RegisteredApp) => {
                            this.toastService.success('Successfully registered the application with the instance', 'Success');
                            return fromAuthorize.registerApplicationSuccess({
                                id: registeredApp.id,
                                appName: registeredApp.name,
                                website: registeredApp.website,
                                clientId: registeredApp.clientId,
                                clientSecret: registeredApp.clientSecret,
                            })
                        }),
                        catchError((error) => {
                            this.toastService.danger('Could not register application. Please check the instance name.', 'Error');
                            return of(fromAuthorize.registerApplicationError({error}));
                        }),
                    )
            )
        )
    );

    getAccessToken$ = createEffect(() =>
        this.actions$.pipe(
            ofType(fromAuthorize.getAccessToken),
            switchMap((action) =>
                this.mastodonApiAuthService
                    .getAccessToken(action.instanceName!, action.clientId!, action.clientSecret!, action.redirectUrl!, action.code)
                    .pipe(
                        map(accessToken => {
                            return {action, accessToken};
                        })
                    )
            ),
            switchMap((result) =>
                this.mastodonApiAuthService
                    .verifyCredentials(result.action.instanceName, result.accessToken)
                    .pipe(
                        map((accountId) => {
                            return {accessToken: result.accessToken, accountId};
                        })
                    )
            ),
            map((result) => {
                this.toastService.success('User successfully authenticated', 'Success');
                return fromAuthorize.getAccessTokenSuccess({accessToken: result.accessToken, accountId: result.accountId});
            }),
            catchError((error) => {
                console.error(error);
                this.toastService.danger('Could not get access token', 'Error');
                return of(fromAuthorize.getAccessTokenError());
            }),
        )
    );

    authorizeUser$ = createEffect(() =>
        this.actions$.pipe(
            ofType(fromAuthorize.authorizeUser),
            map((action) => {
                this.mastodonApiAuthService.authorizeUser(action.instanceName!, action.clientId!, action.redirectUrl!);
            })
        ), {dispatch: false});

    constructor(
        private store: Store,
        private actions$: Actions,
        private mastodonApiAuthService: MastodonApiAuthenticationService,
        private toastService: NbToastrService,
    ) {
    }
}
