import { TestBed } from '@angular/core/testing';
import { provideRouter, Router } from '@angular/router';
import { of, throwError } from 'rxjs';

import { AuthService } from '../../../../core/services/auth/auth.service';
import { ModalService } from '../../../../core/services/modal.service';
import { ToastService } from '../../../../core/services/toast.service';
import { RegisterPageComponent } from './register-page.component';

describe('RegisterPageComponent', () => {
  beforeEach(() => {
    TestBed.resetTestingModule();
  });

  it('shows and hides both password fields with either visibility control', async () => {
    await TestBed.configureTestingModule({
      imports: [RegisterPageComponent],
      providers: [
        provideRouter([]),
        { provide: AuthService, useValue: { register: vi.fn() } },
        { provide: ModalService, useValue: { openSimple: vi.fn() } },
        { provide: ToastService, useValue: { danger: vi.fn() } }
      ]
    }).compileComponents();

    const fixture = TestBed.createComponent(RegisterPageComponent);
    fixture.detectChanges();

    const getPasswordInputs = () =>
      Array.from(
        fixture.nativeElement.querySelectorAll(
          'input#register-password, input#register-password-repeat'
        )
      ) as HTMLInputElement[];
    const getVisibilityButtons = () =>
      Array.from(
        fixture.nativeElement.querySelectorAll('button[aria-label]')
      ) as HTMLButtonElement[];

    expect(getPasswordInputs().map((input) => input.type)).toEqual(['password', 'password']);

    getVisibilityButtons()[0].click();
    fixture.detectChanges();

    expect(getPasswordInputs().map((input) => input.type)).toEqual(['text', 'text']);
    expect(getVisibilityButtons().map((button) => button.getAttribute('aria-label'))).toEqual([
      'Ocultar contraseña',
      'Ocultar contraseña'
    ]);

    getVisibilityButtons()[1].click();
    fixture.detectChanges();

    expect(getPasswordInputs().map((input) => input.type)).toEqual(['password', 'password']);
  });

  it('submits registration data and redirects to /login on success', async () => {
    const authService = {
      register: vi.fn().mockReturnValue(
        of({
          message: 'Usuario registrado correctamente.',
          data: {
            id: 1,
            nombre_apellido: 'Ada Lovelace',
            email: 'ada@example.com'
          }
        })
      )
    };
    const modalService = {
      openSimple: vi.fn().mockReturnValue(of(undefined))
    };
    const toastService = {
      danger: vi.fn()
    };

    await TestBed.configureTestingModule({
      imports: [RegisterPageComponent],
      providers: [
        provideRouter([]),
        { provide: AuthService, useValue: authService },
        { provide: ModalService, useValue: modalService },
        { provide: ToastService, useValue: toastService }
      ]
    }).compileComponents();

    const fixture = TestBed.createComponent(RegisterPageComponent);
    const component = fixture.componentInstance as any;
    const router = TestBed.inject(Router);
    const navigateSpy = vi.spyOn(router, 'navigate').mockResolvedValue(true);

    component.form.setValue({
      nombre_apellido: 'Ada Lovelace',
      email: 'ada@example.com',
      password: 'Secret!123',
      password_confirmation: 'Secret!123'
    });

    component.onSubmit();

    expect(authService.register).toHaveBeenCalledWith({
      nombre_apellido: 'Ada Lovelace',
      email: 'ada@example.com',
      password: 'Secret!123',
      password_confirmation: 'Secret!123'
    });
    expect(modalService.openSimple).toHaveBeenCalledWith({
      content: 'Tu cuenta fue creada correctamente',
      buttonLabel: 'Cerrar'
    });
    expect(navigateSpy).toHaveBeenCalledWith(['/login']);
  });

  it('shows a mismatch message when passwords do not match', async () => {
    const authService = {
      register: vi.fn()
    };
    const modalService = {
      openSimple: vi.fn()
    };
    const toastService = {
      danger: vi.fn()
    };

    await TestBed.configureTestingModule({
      imports: [RegisterPageComponent],
      providers: [
        provideRouter([]),
        { provide: AuthService, useValue: authService },
        { provide: ModalService, useValue: modalService },
        { provide: ToastService, useValue: toastService }
      ]
    }).compileComponents();

    const fixture = TestBed.createComponent(RegisterPageComponent);
    const component = fixture.componentInstance as any;

    component.form.setValue({
      nombre_apellido: 'Ada Lovelace',
      email: 'ada@example.com',
      password: 'secret123',
      password_confirmation: 'different'
    });
    component.onSubmit();

    expect(authService.register).not.toHaveBeenCalled();
    expect(component.getControlError('password_confirmation')).toBe('Las contraseñas no coinciden.');
  });

  it('validates max length and password minimum length before submit', async () => {
    const authService = {
      register: vi.fn()
    };
    const modalService = {
      openSimple: vi.fn()
    };
    const toastService = {
      danger: vi.fn()
    };

    await TestBed.configureTestingModule({
      imports: [RegisterPageComponent],
      providers: [
        provideRouter([]),
        { provide: AuthService, useValue: authService },
        { provide: ModalService, useValue: modalService },
        { provide: ToastService, useValue: toastService }
      ]
    }).compileComponents();

    const fixture = TestBed.createComponent(RegisterPageComponent);
    const component = fixture.componentInstance as any;

    component.form.setValue({
      nombre_apellido: 'A'.repeat(256),
      email: `${'a'.repeat(250)}@example.com`,
      password: '1234567',
      password_confirmation: '1234567'
    });
    component.onSubmit();

    expect(authService.register).not.toHaveBeenCalled();
    expect(component.getControlError('nombre_apellido')).toBe('No puede superar los 255 caracteres.');
    expect(component.getControlError('email')).toBe('No puede superar los 255 caracteres.');
    expect(component.getControlError('password')).toBe('Debe tener al menos 8 caracteres.');
  });

  it('surfaces backend register errors', async () => {
    const authService = {
      register: vi.fn().mockReturnValue(
        throwError(() => ({
          error: {
            errors: {
              email: ['El email ya esta en uso.']
            }
          }
        }))
      )
    };
    const modalService = {
      openSimple: vi.fn()
    };
    const toastService = {
      danger: vi.fn()
    };

    await TestBed.configureTestingModule({
      imports: [RegisterPageComponent],
      providers: [
        provideRouter([]),
        { provide: AuthService, useValue: authService },
        { provide: ModalService, useValue: modalService },
        { provide: ToastService, useValue: toastService }
      ]
    }).compileComponents();

    const fixture = TestBed.createComponent(RegisterPageComponent);
    const component = fixture.componentInstance as any;

    component.form.setValue({
      nombre_apellido: 'Ada Lovelace',
      email: 'ada@example.com',
      password: 'Secret!123',
      password_confirmation: 'Secret!123'
    });
    component.onSubmit();

    expect(component.serverError()).toBe('El email ya esta en uso.');
    expect(toastService.danger).toHaveBeenCalledWith('El email ya esta en uso.');
  });
});
