/* eslint-disable @typescript-eslint/require-await */
/* eslint-disable @typescript-eslint/no-misused-promises */
import { CommonModule } from '@angular/common';
import { Component, inject } from '@angular/core';
import {
  FormControl,
  FormGroup,
  FormsModule,
  ReactiveFormsModule,
  Validators,
} from '@angular/forms';
import {
  ActivatedRoute,
  NavigationExtras,
  Router,
  RouterLink,
} from '@angular/router';
import { EditPasswordDto, LinkVerificationDto } from '@api/models';
import { AuthService } from '@core/services';
import { MustMatch } from '@core/validators/password-must-match.validator';
import { RxState } from '@rx-angular/state';
import { ToastMessageOptions } from 'primeng/api';
import { ButtonModule } from 'primeng/button';
import { CheckboxModule } from 'primeng/checkbox';
import { DividerModule } from 'primeng/divider';
import { InputTextModule } from 'primeng/inputtext';
import { MessagesModule } from 'primeng/messages';
import { PasswordModule } from 'primeng/password';
import { ProgressSpinnerModule } from 'primeng/progressspinner';
import { RippleModule } from 'primeng/ripple';
import { catchError, delay, endWith, map, of, startWith, tap } from 'rxjs';
import { RecoveryPasswordService } from './recovery-password.service';

const recoveryFormGroupFunc = () => ({
  email: new FormControl<string | null>(null, {
    validators: [Validators.required, Validators.email],
  }),
});
export type RecoveryForm = FormGroup<ReturnType<typeof recoveryFormGroupFunc>>;
export type RecoveryFormValue = RecoveryForm['value'];

const setPasswordFormGroupFunc = () => ({
  password: new FormControl<string>('', {
    nonNullable: true,
    validators: [
      Validators.required,
      Validators.minLength(8),
      Validators.pattern(/^(?=.*[a-z])(?=.*[A-Z])(?=.*\d)(?=.*\W).{8,}$/),
    ],
  }),
  confirmPassword: new FormControl<string>('', {
    nonNullable: true,
    validators: [Validators.required],
  }),
});
export type SetPasswordForm = FormGroup<
  ReturnType<typeof setPasswordFormGroupFunc>
>;
export type SetPasswordFormValue = SetPasswordForm['value'];

export interface recoveryState {
  submitted: boolean;
  isLoading: boolean;
  showRecovery: boolean;
  showReset: boolean;
}
type State = recoveryState;

@Component({
  templateUrl: './recovery-password.component.html',
  standalone: true,
  imports: [
    RouterLink,
    CommonModule,
    InputTextModule,
    FormsModule,
    ReactiveFormsModule,
    ButtonModule,
    MessagesModule,
    CheckboxModule,
    FormsModule,
    RippleModule,
    PasswordModule,
    DividerModule,
    ProgressSpinnerModule,
  ],
  providers: [RxState],
})
export class RecoveryPasswordComponent {
  private state = inject(RxState<State>);

  showTransitionOptions = '500ms';
  model$ = this.state.select();

  recoveryForm = new FormGroup(recoveryFormGroupFunc());
  setPasswordForm = new FormGroup(setPasswordFormGroupFunc(), {
    validators: MustMatch('password', 'confirmPassword'),
  });

  messages: ToastMessageOptions[] = [];
  urlP: string | undefined;

  constructor(
    private authService: AuthService,
    public recoveryService: RecoveryPasswordService,
    private activatedRoute: ActivatedRoute,
    private router: Router,
  ) {
    this.authService.purgeAuth();
    this.urlP = this.router.url.split('/').pop();
    this.state.set({
      submitted: false,
      isLoading: false,
      showRecovery: false,
      showReset: false,
    });

    this.activatedRoute.queryParamMap.subscribe(async (params) => {
      const id = Number(params.get('code'));
      const username = params.get('username');
      const token = params.get('token');
      if (id && username && token) {
        this.linkVerification({ id, username, token });
      } else {
        this.state.set({ showRecovery: true });
      }
    });
  }

  submit() {
    this.state.set({ submitted: true, isLoading: false });
    this.messages = [];

    if (this.recoveryForm.invalid) {
      return;
    }
    const form = this.recoveryForm.value;
    const params = {
      username: form.email!,
    };
    this.recoveryForm.disable();
    const recovery$ = this.authService.recoverPassword(params).pipe(
      catchError((err) => {
        this.messages = [
          {
            severity: 'error',
            summary: 'Attenzione!',
            detail:
              'Impossibile effettuare il recupero password in questo momento, riprova più tardi',
          },
        ];
        return of(null);
      }),
      tap((res) => {
        this.recoveryForm.enable();
        if (!res) return;
        this.messages = [
          {
            severity: 'success',
            summary: 'Ci siamo quasi!',
            detail:
              'Se risulti iscritto riceverai una mail con il link per ripristinare la password',
          },
        ];
        this.state.set({ showRecovery: false });
      }),
      map(() => ({})),
      startWith({ isLoading: true }),
      endWith({ isLoading: false }),
    );
    this.state.connect(recovery$);
  }

  linkVerification(params: LinkVerificationDto) {
    const verify$ = this.authService.linkVerification(params).pipe(
      delay(500),
      catchError((err) => {
        this.messages = [
          {
            severity: 'error',
            summary: err.error.title || 'Attenzione!',
            detail: err.error.message || 'Link non valido o scaduto',
          },
        ];
        this.state.set({ showReset: false });
        return of(null);
      }),
      tap((res) => {
        if (!res) return;
        this.state.set({ showReset: true });
      }),
      map(() => ({})),
      startWith({ isLoading: true }),
      endWith({ isLoading: false }),
    );
    this.state.connect(verify$);
  }

  submitSetPassword() {
    if (this.setPasswordForm.invalid) {
      return;
    }
    const form = this.setPasswordForm.value;
    this.state.set({ isLoading: true });
    this.activatedRoute.queryParamMap.subscribe(async (params) => {
      const id = Number(params.get('code'));
      const username = params.get('username');
      const token = params.get('token');

      if (id && username && token) {
        this.setPassword({ id, username, password: form.password!, token });
      } else {
        this.state.set({ showRecovery: true });
        this.messages = [
          {
            severity: 'error',
            summary: 'Attenzione!',
            detail: `Impossibile ripristinare la password in questo momento, riprova più tardi`,
          },
        ];
        this.state.set({ isLoading: true });
      }
    });
  }

  setPassword(params: EditPasswordDto) {
    this.setPasswordForm.disable();
    const setPassword$ = this.authService.setPassword(params).pipe(
      catchError((err) => {
        this.messages = [
          {
            severity: 'error',
            summary: err.error.title || 'Attenzione!',
            detail:
              err.error.message ||
              `Impossibile ${
                this.urlP === 'recupera-password' ? 'ripristinare' : 'impostare'
              } la password in questo momento, riprova più tardi`,
          },
        ];
        return of(null);
      }),
      tap((res) => {
        this.setPasswordForm.enable();
        if (!res) return;
        this.state.set({ showReset: false });
        this.showTransitionOptions = '0ms';
        this.messages = [
          {
            severity: 'success',
            summary: `PASSWORD ${
              this.urlP === 'recupera-password' ? 'RIPRISTINATA' : 'IMPOSTATA'
            }!`,
            detail: 'Verrai reindirizzato al login entro 5 secondi...',
          },
        ];
        let timer = 5;
        const interval = setInterval(() => {
          timer -= 1;
          const unit = timer === 1 ? 'secondo' : 'secondi';
          this.messages = [
            {
              severity: 'success',
              summary: `PASSWORD ${
                this.urlP === 'recupera-password' ? 'RIPRISTINATA' : 'IMPOSTATA'
              }!`,
              detail: `Verrai reindirizzato al login entro ${timer} ${unit}...`,
            },
          ];
          if (timer === 0) {
            clearInterval(interval);
            const navigationExtras: NavigationExtras = {
              queryParams: { email: params.username },
            };
            this.router.navigate(['/login'], navigationExtras);
          }
        }, 1000);
      }),
      map(() => ({})),
      startWith({ isLoading: true }),
      endWith({ isLoading: false }),
    );
    this.state.connect(setPassword$);
  }
}
