import { ComponentFixture, TestBed } from '@angular/core/testing';
import { of, throwError } from 'rxjs';
import { ChangePasswordFormComponent } from './change-password-form.component';
import { AuthService } from '../../../../shared/services/auth.service';
import { ToastService } from '../../../../core/services/toast.service';

describe('ChangePasswordFormComponent', () => {
  let fixture: ComponentFixture<ChangePasswordFormComponent>;
  let component: ChangePasswordFormComponent;
  let authSpy: jasmine.SpyObj<AuthService>;
  let toastSpy: jasmine.SpyObj<ToastService>;

  beforeEach(async () => {
    authSpy = jasmine.createSpyObj<AuthService>('AuthService', ['changePassword']);
    toastSpy = jasmine.createSpyObj<ToastService>('ToastService', ['success', 'error']);

    await TestBed.configureTestingModule({
      imports: [ChangePasswordFormComponent],
      providers: [
        { provide: AuthService, useValue: authSpy },
        { provide: ToastService, useValue: toastSpy },
      ],
    }).compileComponents();

    fixture = TestBed.createComponent(ChangePasswordFormComponent);
    component = fixture.componentInstance;
    fixture.detectChanges();
  });

  const fill = (current: string, next: string, confirm: string) => {
    component.form.setValue({
      currentPassword: current,
      newPassword: next,
      confirmPassword: confirm,
    });
  };

  it('is invalid when the new password is weak', () => {
    fill('Old1234!', 'weak', 'weak');
    expect(component.form.invalid).toBeTrue();
  });

  it('is invalid when confirm does not match', () => {
    fill('Old1234!', 'New1234!', 'Other1234!');
    expect(component.form.invalid).toBeTrue();
  });

  it('is invalid when the new password equals the current password', () => {
    fill('Same1234!', 'Same1234!', 'Same1234!');
    expect(component.form.invalid).toBeTrue();
  });

  it('is valid for a strong, matching, different new password', () => {
    fill('Old1234!', 'New1234!', 'New1234!');
    expect(component.form.valid).toBeTrue();
  });

  it('does not call the service when submitting an invalid form', () => {
    fill('Old1234!', 'weak', 'weak');
    component.onSubmit();
    expect(authSpy.changePassword).not.toHaveBeenCalled();
  });

  it('calls the service with current+new and shows success + resets on 204', () => {
    authSpy.changePassword.and.returnValue(of(void 0));
    fill('Old1234!', 'New1234!', 'New1234!');

    component.onSubmit();

    expect(authSpy.changePassword).toHaveBeenCalledWith('Old1234!', 'New1234!');
    expect(toastSpy.success).toHaveBeenCalled();
    expect(component.form.get('newPassword')?.value).toBeNull();
  });

  it('shows the server error message on failure', () => {
    authSpy.changePassword.and.returnValue(
      throwError(() => ({ error: { message: 'Incorrect password.' } }))
    );
    fill('Wrong1234!', 'New1234!', 'New1234!');

    component.onSubmit();

    expect(toastSpy.error).toHaveBeenCalledWith('Incorrect password.');
  });
});
