import { inject, Injectable } from '@angular/core';
import { Router } from '@angular/router';

import { NgbModal } from '@ng-bootstrap/ng-bootstrap';
import { Action, Selector, State, StateContext, Store } from '@ngxs/store';
import { tap } from 'rxjs/operators';

import { AccountClearAction } from '../action/account.action';
import {
  AuthClearAction,
  ForgotPassWordAction,
  LoginAction,
  LoginWithNumberAction,
  LogoutAction,
  RegisterAction,
  UpdatePasswordAction,
  VerifyEmailOtpAction,
  VerifyNumberOTPAction,
} from '../action/auth.action';
import { ClearCartAction } from '../action/cart.action';
import { AddToWishlistAction } from '../action/wishlist.action';
import { IAuthNumberLoginState } from '../interface/auth.interface';
import { AuthService } from '../services/auth.service';
import { NotificationService } from '../services/notification.service';

export interface AuthStateModel {
  email: String;
  number: IAuthNumberLoginState | null;
  token: String | Number;
  access_token: String | null;
  permissions: [];
}

@State<AuthStateModel>({
  name: 'auth',
  defaults: {
    email: '',
    token: '',
    number: null,
    access_token: '',
    permissions: [],
  },
})
@Injectable()
export class AuthState {
  private store = inject(Store);
  private notificationService = inject(NotificationService);
  public router = inject(Router);
  private modalService = inject(NgbModal);
  private authService = inject(AuthService);

  @Selector()
  static accessToken(state: AuthStateModel): String | null {
    return state.access_token;
  }

  @Selector()
  static isAuthenticated(state: AuthStateModel): Boolean {
    return !!state.access_token;
  }

  @Selector()
  static email(state: AuthStateModel): String {
    return state.email;
  }

  @Selector()
  static number(state: AuthStateModel): IAuthNumberLoginState | null {
    return state.number;
  }

  @Selector()
  static token(state: AuthStateModel): String | Number {
    return state.token;
  }

  @Action(RegisterAction)
  register(ctx: StateContext<AuthStateModel>, action: RegisterAction) {
    return this.authService.register(action.payload).pipe(
      tap({
        next: result => {
          const state = ctx.getState();
          ctx.patchState({
            ...state,
            access_token: result.access_token,
          });
        },
        error: err => {
          throw new Error(err?.error?.message);
        },
      }),
    );
  }

  @Action(LoginAction)
  login(ctx: StateContext<AuthStateModel>, action: LoginAction) {
    this.notificationService.notification = false;
    return this.authService.login(action.payload).pipe(
      tap({
        next: result => {
          ctx.patchState({
            access_token: result.access_token,
            permissions: [],
          });
        },
        error: err => {
          throw new Error(err?.error?.message);
        },
        complete: () => {
          if (localStorage.getItem('wishlist')) {
            this.store.dispatch(
              new AddToWishlistAction({ product_id: localStorage.getItem('wishlist') }),
            );
          }
        },
      }),
    );
  }

  @Action(LoginWithNumberAction)
  loginWithNumber(ctx: StateContext<AuthStateModel>, action: LoginWithNumberAction) {
    this.notificationService.notification = false;
    return this.authService.loginWithNumber(action.payload).pipe(
      tap({
        next: _result => {
          const state = ctx.getState();
          ctx.patchState({
            ...state,
            number: action.payload,
          });
        },
        error: err => {
          throw new Error(err?.error?.message);
        },
        complete: () => {
          this.notificationService.showSuccess('Login Successfully.');
          if (localStorage.getItem('wishlist')) {
            this.store.dispatch(
              new AddToWishlistAction({ product_id: localStorage.getItem('wishlist') }),
            );
          }
        },
      }),
    );
  }

  @Action(ForgotPassWordAction)
  forgotPassword(ctx: StateContext<AuthStateModel>, action: ForgotPassWordAction) {
    this.notificationService.notification = false;
    return this.authService.forgotPassword(action.payload).pipe(
      tap({
        next: () => {
          const state = ctx.getState();
          ctx.patchState({
            ...state,
            email: action.payload.email,
          });
        },
        error: err => {
          throw new Error(err?.error?.message);
        },
      }),
    );
  }

  @Action(VerifyEmailOtpAction)
  verifyEmail(ctx: StateContext<AuthStateModel>, action: VerifyEmailOtpAction) {
    this.notificationService.notification = false;
    return this.authService.verifyEmailOtp(action.payload).pipe(
      tap({
        next: () => {
          const state = ctx.getState();
          ctx.patchState({
            ...state,
            token: action.payload.token,
          });
        },
        error: err => {
          throw new Error(err?.error?.message);
        },
      }),
    );
  }

  @Action(VerifyNumberOTPAction)
  verifyNumber(ctx: StateContext<AuthStateModel>, action: VerifyNumberOTPAction) {
    this.notificationService.notification = false;
    return this.authService.verifyNumberOtp(action.payload).pipe(
      tap({
        next: result => {
          ctx.patchState({
            access_token: result.access_token,
            permissions: [],
          });
        },
        error: err => {
          throw new Error(err?.error?.message);
        },
      }),
    );
  }

  @Action(UpdatePasswordAction)
  updatePassword(_ctx: StateContext<AuthStateModel>, action: UpdatePasswordAction) {
    this.notificationService.notification = false;
    return this.authService.updatePassword(action.payload).pipe(
      tap({
        error: err => {
          throw new Error(err?.error?.message);
        },
      }),
    );
  }

  @Action(LogoutAction)
  logout(_ctx: StateContext<AuthStateModel>) {
    this.notificationService.notification = false;
    return this.authService.logout().pipe(
      tap({
        next: _result => {
          this.store.dispatch(new AuthClearAction());
        },
        complete: () => {
          this.modalService.dismissAll();
        },
        error: err => {
          throw new Error(err?.error?.message);
        },
      }),
    );
  }

  @Action(AuthClearAction)
  authClear(ctx: StateContext<AuthStateModel>) {
    ctx.patchState({
      email: '',
      token: '',
      access_token: null,
      permissions: [],
    });
    this.authService.redirectUrl = undefined;
    this.store.dispatch(new AccountClearAction());
    this.store.dispatch(new ClearCartAction());
  }
}
