import { ChangeDetectionStrategy, Component, inject, signal, viewChildren } from '@angular/core';
import { FormBuilder, ReactiveFormsModule, Validators } from '@angular/forms';
import { ActivatedRoute, Router } from '@angular/router';

import { AuthService } from '../../../../core/services/auth/auth.service';
import { ToastService } from '../../../../core/services/toast.service';
import { ButtonComponent } from '../../../../shared/components/button/button.component';
import { InputComponent } from '../../../../shared/components/input/input.component';

type CodeControlName = 'digit1' | 'digit2' | 'digit3' | 'digit4';
const CODE_CONTROL_NAMES: CodeControlName[] = ['digit1', 'digit2', 'digit3', 'digit4'];

@Component({
  selector: 'app-recover-password-code-page',
  imports: [ReactiveFormsModule, InputComponent, ButtonComponent],
  templateUrl: './recover-password-code-page.component.html',
  styleUrl: './recover-password-code-page.component.scss',
  changeDetection: ChangeDetectionStrategy.OnPush,
})
export class RecoverPasswordCodePageComponent {
  private readonly formBuilder = inject(FormBuilder);
  private readonly router = inject(Router);
  private readonly route = inject(ActivatedRoute);
  private readonly authService = inject(AuthService);
  private readonly toastService = inject(ToastService);
  private readonly submittedState = signal(false);
  private readonly isSubmittingState = signal(false);
  private readonly isResendingState = signal(false);
  private readonly serverErrorState = signal<string | null>(null);
  private readonly digitInputs = viewChildren(InputComponent);

  protected readonly email = this.route.snapshot.queryParamMap.get('email') ?? '';
  protected readonly form = this.formBuilder.nonNullable.group({
    digit1: ['', [Validators.required, Validators.pattern(/^\d$/)]],
    digit2: ['', [Validators.required, Validators.pattern(/^\d$/)]],
    digit3: ['', [Validators.required, Validators.pattern(/^\d$/)]],
    digit4: ['', [Validators.required, Validators.pattern(/^\d$/)]],
  });
  protected readonly submitted = this.submittedState.asReadonly();
  protected readonly isSubmitting = this.isSubmittingState.asReadonly();
  protected readonly isResending = this.isResendingState.asReadonly();
  protected readonly serverError = this.serverErrorState.asReadonly();

  protected updateDigit(controlName: CodeControlName, value: string | number): void {
    const digit = String(value).replace(/\D/g, '').slice(-1);
    this.form.controls[controlName].setValue(digit);

    const currentIndex = CODE_CONTROL_NAMES.indexOf(controlName);
    if (digit && currentIndex < CODE_CONTROL_NAMES.length - 1) {
      this.digitInputs()[currentIndex + 1]?.focus();
    }
  }

  protected pasteCode(event: ClipboardEvent): void {
    event.preventDefault();

    const pastedText = event.clipboardData?.getData('text') ?? '';
    const digits = pastedText.replace(/\D/g, '');

    if (digits.length !== CODE_CONTROL_NAMES.length) {
      console.warn('Password reset code paste was rejected because it did not contain four digits.', {
        digitCount: digits.length,
      });
      this.showServerError('Pegá un código de cuatro dígitos.');
      return;
    }

    CODE_CONTROL_NAMES.forEach((controlName, index) => {
      this.form.controls[controlName].setValue(digits[index]);
    });

    this.submittedState.set(false);
    this.serverErrorState.set(null);
    this.digitInputs()[CODE_CONTROL_NAMES.length - 1]?.focus();
  }

  protected isCodeInvalid(): boolean {
    return this.form.invalid && this.submitted();
  }

  protected onSubmit(): void {
    this.submittedState.set(true);
    this.serverErrorState.set(null);

    if (this.form.invalid || this.isSubmitting()) {
      this.form.markAllAsTouched();
      return;
    }

    const code = Object.values(this.form.getRawValue()).join('');

    if (!this.email) {
      console.warn('Password reset code validation cannot start without an email.');
      this.showServerError('No se pudo identificar la solicitud de recuperación.');
      return;
    }

    this.isSubmittingState.set(true);

    this.authService.validatePasswordResetCode(this.email, code).subscribe({
      next: (response) => {
        this.isSubmittingState.set(false);

        if (response.status !== 200 || response.body?.status !== 'validated') {
          console.warn('Password reset code validation returned an unexpected status.', {
            httpStatus: response.status,
            attemptStatus: response.body?.status ?? null,
          });
          this.showServerError('No se pudo validar el código. Intenta nuevamente.');
          return;
        }

        void this.router.navigate(['/recuperar-contrasena/restablecer'], {
          queryParams: {
            email: this.email,
            code,
          },
        });
      },
      error: (error: unknown) => {
        this.isSubmittingState.set(false);
        console.error('Password reset code validation request failed.', error);
        this.showServerError(this.resolveErrorMessage(error));
      },
    });
  }

  protected resendCode(): void {
    if (!this.email || this.isResending()) {
      return;
    }

    this.serverErrorState.set(null);
    this.isResendingState.set(true);

    this.authService.requestPasswordReset(this.email).subscribe({
      next: (response) => {
        this.isResendingState.set(false);

        if (response.status !== 202 || response.body?.status !== 'pending') {
          console.warn('Password reset code resend returned an unexpected status.', {
            httpStatus: response.status,
            attemptStatus: response.body?.status ?? null,
          });
          this.showServerError('No se pudo reenviar el código. Intenta nuevamente.');
          return;
        }

        this.submittedState.set(false);
        this.form.reset();
        this.digitInputs()[0]?.focus();
        this.toastService.success('Código reenviado correctamente.');
      },
      error: (error: unknown) => {
        this.isResendingState.set(false);
        console.error('Password reset code resend request failed.', error);
        this.showServerError(this.resolveErrorMessage(error));
      },
    });
  }

  protected goBack(): void {
    void this.router.navigate(['/recuperar-contrasena'], {
      queryParams: this.email ? { email: this.email } : undefined,
    });
  }

  private showServerError(message: string): void {
    this.serverErrorState.set(message);
    this.toastService.danger(message);
  }

  private resolveErrorMessage(error: unknown): string {
    const errorPayload =
      typeof error === 'object' && error !== null && 'error' in error
        ? (error as { error?: { errors?: Record<string, string[]>; message?: string } }).error
        : undefined;
    const codeMessages = errorPayload?.errors?.['codigo'];
    const codeError = Array.isArray(codeMessages) ? codeMessages[0] : null;

    if (typeof codeError === 'string' && codeError.trim()) {
      return codeError;
    }

    if (typeof errorPayload?.message === 'string' && errorPayload.message.trim()) {
      return errorPayload.message;
    }

    return 'No se pudo validar el código. Intenta nuevamente.';
  }
}
