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

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

const PASSWORD_MIN_LENGTH = 8;
const TEXT_MAX_LENGTH = 255;

const passwordsMatchValidator: ValidatorFn = (
  control: AbstractControl
): ValidationErrors | null => {
  const password = control.get('password')?.value;
  const passwordConfirmation = control.get('password_confirmation')?.value;

  if (!password || !passwordConfirmation) {
    return null;
  }

  return password === passwordConfirmation ? null : { passwordMismatch: true };
};

@Component({
  selector: 'app-register-page',
  imports: [ReactiveFormsModule, InputComponent, ButtonComponent],
  templateUrl: './register-page.component.html',
  styleUrl: './register-page.component.scss',
  changeDetection: ChangeDetectionStrategy.OnPush
})
export class RegisterPageComponent {
  private readonly formBuilder = inject(FormBuilder);
  private readonly router = inject(Router);
  private readonly authService = inject(AuthService);
  private readonly modalService = inject(ModalService);
  private readonly toastService = inject(ToastService);

  private readonly submittedState = signal(false);
  private readonly serverErrorState = signal<string | null>(null);
  private readonly isSubmittingState = signal(false);

  protected readonly form = this.formBuilder.nonNullable.group({
    nombre_apellido: ['', [Validators.required, Validators.maxLength(TEXT_MAX_LENGTH)]],
    email: [
      '',
      [Validators.required, Validators.email, Validators.maxLength(TEXT_MAX_LENGTH)]
    ],
    password: ['', [
      Validators.required,
      Validators.minLength(PASSWORD_MIN_LENGTH),
      Validators.pattern(/^(?=.*[a-z])(?=.*[A-Z])(?=.*[\W_]).+$/)
    ]],
    password_confirmation: ['', [Validators.required]]
  }, {
    validators: [passwordsMatchValidator]
  });
  protected readonly submitted = this.submittedState.asReadonly();
  protected readonly serverError = this.serverErrorState.asReadonly();
  protected readonly isSubmitting = this.isSubmittingState.asReadonly();

  goToLogin(): void {
    void this.router.navigate(['/login']);
  }

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

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

    this.isSubmittingState.set(true);

    this.authService.register(this.form.getRawValue()).subscribe({
      next: () => {
        this.isSubmittingState.set(false);
        this.modalService.openSimple({
          content: 'Tu cuenta fue creada correctamente',
          buttonLabel: 'Cerrar'
        }).subscribe(() => {
          void this.router.navigate(['/login']);
        });
      },
      error: (error: unknown) => {
        this.isSubmittingState.set(false);
        const errorMessage = this.resolveErrorMessage(error);
        this.serverErrorState.set(errorMessage);
        this.toastService.danger(errorMessage);
      }
    });
  }

  protected updateField(
    controlName: 'nombre_apellido' | 'email' | 'password' | 'password_confirmation',
    value: string | number
  ): void {
    this.form.controls[controlName].setValue(String(value));
  }

  protected showControlError(
    controlName: 'nombre_apellido' | 'email' | 'password' | 'password_confirmation'
  ): boolean {
    const control = this.form.controls[controlName];
    const hasPasswordMismatch =
      controlName === 'password_confirmation' &&
      this.form.hasError('passwordMismatch') &&
      (control.touched || this.submitted());

    return (control.invalid && (control.touched || this.submitted())) || hasPasswordMismatch;
  }

  protected getControlError(
    controlName: 'nombre_apellido' | 'email' | 'password' | 'password_confirmation'
  ): string | null {
    const control = this.form.controls[controlName];

    if (!this.showControlError(controlName)) {
      return null;
    }

    if (control.hasError('required')) {
      return 'Este campo es obligatorio.';
    }

    if (control.hasError('maxlength')) {
      return `No puede superar los ${TEXT_MAX_LENGTH} caracteres.`;
    }

    if (control.hasError('email')) {
      return 'Ingresa un email valido.';
    }

    if (control.hasError('minlength')) {
      return `Debe tener al menos ${PASSWORD_MIN_LENGTH} caracteres.`;
    }

    if (controlName === 'password' && control.hasError('pattern')) {
      return 'Debe contener mayuscula, minuscula y un caracter especial.';
    }

    if (controlName === 'password_confirmation' && this.form.hasError('passwordMismatch')) {
      return 'Las contraseñas no coinciden.';
    }

    return 'El valor ingresado no es valido.';
  }

  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 apiErrors = errorPayload?.errors;

    if (apiErrors && typeof apiErrors === 'object') {
      for (const field of ['nombre_apellido', 'email', 'password'] as const) {
        const messages = apiErrors[field];

        if (Array.isArray(messages) && typeof messages[0] === 'string' && messages[0].trim()) {
          return messages[0];
        }
      }
    }

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

    return 'No se pudo crear la cuenta. Intenta nuevamente.';
  }
}
