import { ComponentFixture, TestBed } from '@angular/core/testing';

import { UserAvatarFormComponent } from './user-avatar-form.component';
import { ToastrService } from 'ngx-toastr';
import { mockToastR } from '@app/testing/toastr.mock';
import { UserViewModel } from '../../../adapters/users/user.presenter.model';
import { FileManagerService } from '../../../adapters/shared/services/file-manager.service';
import { UserFacade } from '../../../adapters/users/user.facade';
import { ActionType } from '@app/domain/action-type.util';
import { mockUserRepo, mockUsers } from '@app/testing/user.mock';
import { USER_REPOSITORY_TOKEN } from '@app/infrastructure/users/user-repository.token';
import { provideRouter } from '@angular/router';
import { mockFileManagerSvc } from '@app/testing/file-manager.service.mock';
import { mockUserFac } from '@app/testing/adapters/users/user.facade.mock';

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

  // 1. Définition des Mocks
  let mockFileManagerService = mockFileManagerSvc;
  let mockUserFacade = mockUserFac;

  // Données de test
  const mockUser: UserViewModel = mockUsers[0];

  beforeEach(async () => {
    // Réinitialisation des mocks avant chaque test
    mockFileManagerService.file.set(null);
    mockFileManagerService.imagePreviewUrl.set(null);
    mockFileManagerService.fileError.set(null);
    mockFileManagerService.resetFile.mockClear();
    mockUserFacade.update.mockClear();
    mockUserFacade.loading.set({ isLoading: false, action: ActionType.NONE });

    await TestBed.configureTestingModule({
      imports: [UserAvatarFormComponent],
      providers: [
        provideRouter([]),
        { provide: USER_REPOSITORY_TOKEN, useValue: mockUserRepo },
        { provide: UserFacade, useValue: mockUserFacade },
        { provide: FileManagerService, useValue: mockFileManagerService },
        { provide: ToastrService, useValue: mockToastR },
      ],
    }).compileComponents();

    fixture = TestBed.createComponent(UserAvatarFormComponent);
    component = fixture.componentInstance;

    // Initialisation de l'input requis (Signal Input)
    fixture.componentRef.setInput('user', mockUser);
    fixture.detectChanges();
  });

  it('devrait créer le composant', () => {
    expect(component).toBeTruthy();
  });

  describe("Affichage de l'avatar (currentAvatarUrl)", () => {
    it('devrait prioriser la prévisualisation locale si elle existe', () => {
      mockFileManagerService.imagePreviewUrl.set('data:image/png;base64,preview');
      // On force la détection pour mettre à jour la vue
      fixture.detectChanges();

      expect(component.currentAvatarUrl).toBe('data:image/png;base64,preview');
    });

    it("devrait afficher un avatar Dicebear si l'utilisateur n'a pas d'avatar", () => {
      const userNoAvatar = { ...mockUser, avatar: null };
      fixture.componentRef.setInput('user', userNoAvatar);
      fixture.detectChanges();

      expect(component.currentAvatarUrl).toContain('api.dicebear.com');
      // Vérifie que le seed utilise le nom
      expect(component.currentAvatarUrl).toContain(
        'https://api.dicebear.com/9.x/initials/svg?seed=foo'
      );
    });
  });

  describe('Validation du formulaire (canSubmit)', () => {
    it('devrait être false par défaut', () => {
      expect(component.canSubmit).toBe(false);
    });

    it('devrait être true si un fichier est présent et valide', () => {
      mockFileManagerService.file.set(new File([''], 'test.png'));
      mockFileManagerService.fileError.set(null);
      mockUserFacade.loading.set({ isLoading: false, action: ActionType.NONE });

      expect(component.canSubmit).toBe(true);
    });

    it('devrait être false si une erreur de fichier est présente', () => {
      mockFileManagerService.file.set(new File([''], 'test.png'));
      mockFileManagerService.fileError.set('Fichier trop lourd');

      expect(component.canSubmit).toBe(false);
    });

    it('devrait être false si un chargement est en cours', () => {
      mockFileManagerService.file.set(new File([''], 'test.png'));
      mockUserFacade.loading.set({ isLoading: true, action: ActionType.UPDATE });

      expect(component.canSubmit).toBe(false);
    });
  });

  describe('Soumission (onUserAvatarFormSubmit)', () => {
    it('devrait appeler la façade avec FormData si tout est valide', () => {
      const validFile = new File(['content'], 'avatar.jpg');
      mockFileManagerService.file.set(validFile);

      component.onUserAvatarFormSubmit();

      expect(mockUserFacade.update).toHaveBeenCalledTimes(1);

      // Vérification des arguments passés à update
      const args = mockUserFacade.update.mock.calls[0];
      expect(args[0]).toBe('user_001'); // ID User
      expect(args[1]).toBeInstanceOf(FormData); // Le payload doit être un FormData
      expect(args[1].get('avatar')).toBe(validFile); // Le fichier doit être dedans
    });

    it("ne devrait RIEN faire si aucun fichier n'est sélectionné", () => {
      mockFileManagerService.file.set(null);

      component.onUserAvatarFormSubmit();

      expect(mockUserFacade.update).not.toHaveBeenCalled();
    });
  });

  describe('Gestion des effets (Effect)', () => {
    it('devrait réinitialiser le fichier après une mise à jour réussie', () => {
      // 1. On prépare l'état initial
      mockFileManagerService.file.set(new File([''], 'test.jpg'));

      // 2. On déclenche la soumission pour passer le signal 'onSubmitted' à true
      component.onUserAvatarFormSubmit();

      // 3. On simule la FIN du chargement (isLoading passe de true à false)
      // L'effet écoute: !loading().isLoading && action === UPDATE && onSubmitted()
      mockUserFacade.loading.set({ isLoading: false, action: ActionType.UPDATE });

      // Force la détection des changements pour déclencher l'effect Angular
      fixture.detectChanges();

      expect(mockFileManagerService.resetFile).toHaveBeenCalled();
    });

    it("ne devrait PAS réinitialiser le fichier si l'action n'est pas UPDATE", () => {
      component.onUserAvatarFormSubmit();

      // Simulation d'une autre action (ex: READ)
      mockUserFacade.loading.set({ isLoading: false, action: ActionType.READ });
      fixture.detectChanges();

      expect(mockFileManagerService.resetFile).not.toHaveBeenCalled();
    });
  });
});
