import { ComponentFixture, TestBed } from '@angular/core/testing';
import { LoginComponent } from './login.component';
import { provideHttpClient, withInterceptorsFromDi } from '@angular/common/http';
import { FormsModule } from '@angular/forms';
import { ToastrModule } from 'ngx-toastr';
import { BrowserAnimationsModule } from '@angular/platform-browser/animations';
import { MatFormFieldModule } from '@angular/material/form-field';
import { MatInputModule } from '@angular/material/input';
import { MatIconModule } from '@angular/material/icon';
import { TranslateModule } from '@ngx-translate/core';
import { of, throwError } from 'rxjs';
import { ConfigService } from '@services/config.service';

describe('LoginComponent', () => {
  let component: LoginComponent;
  let fixture: ComponentFixture<LoginComponent>;

  beforeEach(async () => {
    const mockConfigService = {
      apiUrl: 'http://mock-api-url',
      mercureUrl: 'http://mock-mercure-url'
    };

    await TestBed.configureTestingModule({
      declarations: [LoginComponent],
      imports: [
        FormsModule,
        ToastrModule.forRoot(),
        BrowserAnimationsModule,
        MatFormFieldModule,
        MatInputModule,
        MatIconModule,
        TranslateModule.forRoot()
      ],
      providers: [
        provideHttpClient(withInterceptorsFromDi()),
        { provide: ConfigService, useValue: mockConfigService }
      ]
    }).compileComponents();

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

  it('should create', () => {
    expect(component).toBeTruthy();
  });

  it('should disable the login button if username or password is missing', () => {
    component.loginObj.username = '';
    component.loginObj.password = '';
    fixture.detectChanges();
    const button = fixture.nativeElement.querySelector('button[type="submit"]');
    expect(button.disabled).toBeTruthy();
  });

  it('should enable the login button if username and password are present', () => {
    component.loginObj.username = 'testUser';
    component.loginObj.password = 'testPass';
    fixture.detectChanges();
    const button = fixture.nativeElement.querySelector('button[type="submit"]');
    expect(button.disabled).toBeFalsy();
  });

  it('should call onLogin and navigate on successful login', () => {
    const mockRouter = spyOn(component['router'], 'navigateByUrl');
    const mockHttp = spyOn(component['http'], 'post').and.returnValue(of({ token: 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c', refreshToken: '456' }));

    component.loginObj.username = 'testUser';
    component.loginObj.password = 'testPass';
    component.onLogin();

    expect(mockHttp).toHaveBeenCalledWith(`${component.baseUrl}/auth/login`, component.loginObj);
    expect(mockRouter).toHaveBeenCalledWith('/groups');
  });

  it('should show error message on login failure', () => {
    const mockToast = spyOn(component['toastService'], 'error');
    const mockHttp = spyOn(component['http'], 'post').and.returnValue(throwError({ error: { message: 'Invalid credentials' } }));

    component.loginObj.username = 'testUser';
    component.loginObj.password = 'testPass';
    component.onLogin();

    expect(mockHttp).toHaveBeenCalled();
    expect(mockToast).toHaveBeenCalledWith('Error al iniciar sesión: Invalid credentials', 'Error');
  });

  it('should change language to Spanish and save to localStorage', () => {
    const mockTranslate = spyOn(component['translateService'], 'use');
    component.changeLanguage('es');
    expect(localStorage.getItem('language')).toBe('es');
    expect(mockTranslate).toHaveBeenCalledWith('es');
  });

  it('should change language to English and save to localStorage', () => {
    const mockTranslate = spyOn(component['translateService'], 'use');
    component.changeLanguage('en');
    expect(localStorage.getItem('language')).toBe('en');
    expect(mockTranslate).toHaveBeenCalledWith('en');
  });

  it('should toggle password visibility when clicking the button', () => {
    const initialHideState = component.hide();
    const button = fixture.nativeElement.querySelector('button[mat-icon-button]');
    button.click();
    expect(component.hide()).toBe(!initialHideState);
  });

  it('should add "invalid" class to username input if it is invalid and touched', () => {
    const usernameInput = fixture.nativeElement.querySelector('input[name="username"]');
    usernameInput.value = ''; // Empty value makes it invalid
    usernameInput.dispatchEvent(new Event('input'));
    usernameInput.dispatchEvent(new Event('blur')); // Simulates "touched"
    fixture.detectChanges();

    expect(usernameInput.classList).toContain('invalid');
  });

  it('should add rotating class to the logo when loading', () => {
    component.isLoading = true;
    fixture.detectChanges();
    const logo = fixture.nativeElement.querySelector('.login-logo');
    expect(logo.classList).toContain('rotating');
  });

  it('should not add rotating class to the logo when not loading', () => {
    component.isLoading = false;
    fixture.detectChanges();
    const logo = fixture.nativeElement.querySelector('.login-logo');
    expect(logo.classList).not.toContain('rotating');
  });

  it('should show a success toast message', () => {
    const mockToast = spyOn(component['toastService'], 'success');
    component.openSnackBar(false, 'Welcome!');
    expect(mockToast).toHaveBeenCalledWith('Welcome!', 'Éxito');
  });

  it('should show an error toast message', () => {
    const mockToast = spyOn(component['toastService'], 'error');
    component.openSnackBar(true, 'Something went wrong');
    expect(mockToast).toHaveBeenCalledWith('Something went wrong', 'Error');
  });
});
