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

import { ProjectPictureFormComponent } from './project-picture-form.component';
import { mockProjects } from '@app/testing/project.mock';
import { mockFileManagerSvc } from '@app/testing/file-manager.service.mock';
import { mockProjectFac } from '@app/testing/adapters/projects/project.facade.mock';
import { ProjectViewModel } from '../../../adapters/projects/project.presenter.model';
import { ProjectFacade } from '../../../adapters/projects/project.facade';
import { FileManagerService } from '../../../adapters/shared/services/file-manager.service';
import { ActionType } from '@app/domain/action-type.util';

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

  // 1. Mocks des services
  const mockFileManagerService = mockFileManagerSvc;

  const mockProjectFacade = mockProjectFac;

  // Données de test
  const mockProject: ProjectViewModel = mockProjects[0];

  beforeEach(async () => {
    // Reset des mocks
    mockFileManagerService.file.set(null);
    mockFileManagerService.imagePreviewUrl.set(null);
    mockFileManagerService.fileError.set(null);
    mockFileManagerService.resetFile.mockClear();

    mockProjectFacade.update.mockClear();
    mockProjectFacade.loading.set({ isLoading: false, action: ActionType.NONE });
    mockProjectFacade.error.set({ hasError: false });

    await TestBed.configureTestingModule({
      imports: [ProjectPictureFormComponent],
      providers: [
        { provide: ProjectFacade, useValue: mockProjectFacade },
        { provide: FileManagerService, useValue: mockFileManagerService },
      ],
    }).compileComponents();

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

    // Initialisation de l'input requis
    fixture.componentRef.setInput('project', mockProject);
    fixture.detectChanges();
  });

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

  describe("Affichage de l'image (currentImageUrl)", () => {
    it('devrait prioriser la prévisualisation locale (upload en cours)', () => {
      mockFileManagerService.imagePreviewUrl.set('data:image/png;base64,preview');
      fixture.detectChanges();

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

    it("devrait afficher l'image du serveur si pas de preview", () => {
      // mockProject a 'image-serveur.jpg'
      expect(component.currentImageUrl).toContain('portfolio-preview.png');
    });

    /*it('devrait générer une image Dicebear avec le nom du projet si aucune image', () => {
      const projectNoImg = { ...mockProject, fichier: undefined };
      fixture.componentRef.setInput('project', projectNoImg);
      fixture.detectChanges();

      expect(component.currentImageUrl).toContain('api.dicebear.com');
      expect(component.currentImageUrl).toContain('Web 3D');
    });*/

    /*it("devrait générer une image par défaut si le projet n'a ni image ni nom", () => {
      const emptyProject = { ...mockProject, fichier: undefined, nom: undefined };
      fixture.componentRef.setInput('project', emptyProject);
      fixture.detectChanges();

      expect(component.currentImageUrl).toContain(undefined);
    });*/
  });

  describe('Validation (canSubmit)', () => {
    it('devrait être true si un fichier est prêt et valide', () => {
      mockFileManagerService.file.set(new File([''], 'img.jpg'));
      mockFileManagerService.fileError.set(null);
      mockProjectFacade.loading.set({ isLoading: false, action: ActionType.NONE });

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

    it('devrait être false si une erreur de fichier existe', () => {
      mockFileManagerService.file.set(new File([''], 'img.jpg'));
      mockFileManagerService.fileError.set('Trop lourd');

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

    it('devrait être false si pas de fichier ni de preview', () => {
      mockFileManagerService.file.set(null);
      mockFileManagerService.imagePreviewUrl.set(null);

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

  describe('Soumission (onSubmit)', () => {
    it('devrait envoyer un FormData à la façade', () => {
      const file = new File(['blob'], 'test.png');
      mockFileManagerService.file.set(file);

      component.onSubmit();

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

      const args = mockProjectFacade.update.mock.calls[0];
      expect(args[0]).toBe('1'); // ID projet
      expect(args[1]).toBeInstanceOf(FormData);
      expect(args[1].get('fichier')).toBe(file);
    });

    it('ne devrait rien faire si pas de fichier', () => {
      mockFileManagerService.file.set(null);
      component.onSubmit();
      expect(mockProjectFacade.update).not.toHaveBeenCalled();
    });
  });

  describe('Effets (Réinitialisation après succès)', () => {
    it("devrait émettre onFormSubmitted et reset le fichier quand l'update réussit", () => {
      // 1. Espionner l'output
      let emitted = false;
      component.onFormSubmitted.subscribe(() => (emitted = true));

      // 2. Déclencher la soumission
      mockFileManagerService.file.set(new File([''], 'test.jpg'));
      component.onSubmit(); // onSubmitted -> true

      // 3. Simuler la fin du chargement succès
      mockProjectFacade.loading.set({ isLoading: false, action: ActionType.UPDATE });

      fixture.detectChanges(); // Déclenche l'effect

      expect(emitted).toBe(true);
      expect(mockFileManagerService.resetFile).toHaveBeenCalled();
    });

    it("ne devrait rien faire si l'action n'est pas UPDATE", () => {
      component.onSubmit();

      mockProjectFacade.loading.set({ isLoading: false, action: ActionType.CREATE });
      fixture.detectChanges();

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