import { signal, Signal, WritableSignal } from '@angular/core';
import {
  createDirectiveFactory,
  SpectatorDirective,
} from '@ngneat/spectator/jest';
import { ScannerReadyDirective } from './render-if-scanner-is-ready.directive';
import { ScannerService } from './scanner.service';

// FULLY MOCK EXTERNAL DEPENDENCIES
jest.mock('scandit-web-datacapture-core', () => ({
  configure: jest.fn(),
}));
jest.mock('scandit-web-datacapture-barcode', () => ({
  barcodeCaptureLoader: jest.fn(() => 'mockedBarcodeLoader'),
}));
const loggerInfo = jest.fn();
const loggerError = jest.fn();
jest.mock('@isa/core/logging', () => ({
  logger: jest.fn(() => ({ info: loggerInfo, error: loggerError })),
}));

/**
 * Unit tests for the ScannerReadyDirective.
 * Tests conditional rendering based on scanner ready state.
 */
describe('ScannerReadyDirective', () => {
  /**
   * Spectator instance for the directive
   */
  let spectator: SpectatorDirective<ScannerReadyDirective>;

  /**
   * Signal to control the scanner ready state
   */
  let readySignal: WritableSignal<boolean>;

  /**
   * Mock of the ScannerService
   */
  let scannerServiceMock: jest.Mocked<ScannerService>;

  const createDirective = createDirectiveFactory({
    directive: ScannerReadyDirective,
    mocks: [ScannerService], // mock out the real ScannerService (and its Config deps)
    detectChanges: false, // manual CD
    template: `<div *sharedScannerReady>Ready</div>`,
  });

  beforeEach(() => {
    // 1) instantiate
    spectator = createDirective();
    // 2) grab the Spectator mock
    scannerServiceMock = spectator.inject(ScannerService);
    // 3) override its `ready` with a real Angular signal
    readySignal = signal(false);
    (scannerServiceMock as any).ready = readySignal;
  });

  it('should render when ready=true', () => {
    // ARRANGE
    readySignal.set(true);
    // ACT
    spectator.detectChanges();
    // ASSERT
    expect(spectator.query('div')).toHaveText('Ready');
    expect(spectator.query('div')).toBeTruthy();
  });

  it('should not render when ready=false', () => {
    // ARRANGE
    readySignal.set(false);
    // ACT
    spectator.detectChanges();
    // ASSERT
    expect(spectator.query('div')).not.toExist();
  });

  it('should update view when ready flips', () => {
    // ARRANGE
    readySignal.set(false);
    spectator.detectChanges();
    expect(spectator.query('div')).not.toExist();

    // ACT
    readySignal.set(true);
    spectator.detectChanges();
    // ASSERT
    expect(spectator.query('div')).toHaveText('Ready');
  });
});
