import { HttpResponse } from '@angular/common/http';
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 { ToastService } from '../../../../core/services/toast.service';
import { RecoverPasswordPageComponent } from './recover-password-page.component';

describe('RecoverPasswordPageComponent', () => {
  let requestPasswordReset: ReturnType<typeof vi.fn>;
  let showDangerToast: ReturnType<typeof vi.fn>;

  beforeEach(() => {
    TestBed.resetTestingModule();
    vi.spyOn(console, 'error').mockImplementation(() => undefined);
    vi.spyOn(console, 'warn').mockImplementation(() => undefined);
    requestPasswordReset = vi.fn(() => of(new HttpResponse({
      body: {
        message: 'Solicitud aceptada.',
        status: 'pending' as const
      },
      status: 202
    })));
    showDangerToast = vi.fn();
  });

  afterEach(() => {
    vi.restoreAllMocks();
  });

  function authProviders() {
    return [
      { provide: AuthService, useValue: { requestPasswordReset } },
      { provide: ToastService, useValue: { danger: showDangerToast } }
    ];
  }

  it('validates the email before submitting', async () => {
    await TestBed.configureTestingModule({
      imports: [RecoverPasswordPageComponent],
      providers: [provideRouter([]), ...authProviders()],
    }).compileComponents();

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

    component.form.controls.email.setValue('invalid-email');
    component.onSubmit();

    expect(component.form.invalid).toBe(true);
    expect(component.getEmailError()).toBe('Ingresa un email válido.');
  });

  it('navigates back to login', async () => {
    await TestBed.configureTestingModule({
      imports: [RecoverPasswordPageComponent],
      providers: [provideRouter([]), ...authProviders()],
    }).compileComponents();

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

    component.goToLogin();

    expect(navigateSpy).toHaveBeenCalledWith(['/login']);
  });

  it('continues to the code page with the entered email', async () => {
    await TestBed.configureTestingModule({
      imports: [RecoverPasswordPageComponent],
      providers: [provideRouter([]), ...authProviders()],
    }).compileComponents();

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

    component.form.controls.email.setValue('ada@example.com');
    component.onSubmit();

    expect(requestPasswordReset).toHaveBeenCalledWith('ada@example.com');
    expect(navigateSpy).toHaveBeenCalledWith(['/recuperar-contrasena/codigo'], {
      queryParams: { email: 'ada@example.com' },
    });
  });

  it('stays on the page when the endpoint does not finish as pending', async () => {
    requestPasswordReset.mockReturnValue(of(new HttpResponse({
      body: null,
      status: 200
    })));

    await TestBed.configureTestingModule({
      imports: [RecoverPasswordPageComponent],
      providers: [provideRouter([]), ...authProviders()],
    }).compileComponents();

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

    component.form.controls.email.setValue('ada@example.com');
    component.onSubmit();

    expect(navigateSpy).not.toHaveBeenCalled();
    expect(component.serverError()).toBe(
      'No se pudo iniciar la recuperación. Intenta nuevamente.',
    );
    expect(showDangerToast).toHaveBeenCalled();
  });

  it('shows the API error and does not navigate when the request fails', async () => {
    requestPasswordReset.mockReturnValue(throwError(() => ({
      error: { message: 'Servicio temporalmente no disponible.' }
    })));

    await TestBed.configureTestingModule({
      imports: [RecoverPasswordPageComponent],
      providers: [provideRouter([]), ...authProviders()],
    }).compileComponents();

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

    component.form.controls.email.setValue('ada@example.com');
    component.onSubmit();

    expect(navigateSpy).not.toHaveBeenCalled();
    expect(component.serverError()).toBe('Servicio temporalmente no disponible.');
    expect(showDangerToast).toHaveBeenCalledWith('Servicio temporalmente no disponible.');
  });
});
