import {
  ChangeDetectionStrategy,
  Component,
  inject,
  input,
  model,
  OnDestroy,
  output,
} from '@angular/core';
import { ControlValueAccessor } from '@angular/forms';
import { logger } from '@isa/core/logging';
import { IconButtonComponent, IconButtonSize } from '@isa/ui/buttons';
import { ScannerReadyDirective } from './render-if-scanner-is-ready.directive';
import { ScannerService } from './scanner.service';

/**
 * A button component that integrates with the scanner service to trigger barcode scanning.
 *
 * Implements ControlValueAccessor to work with Angular forms. This component will only
 * be visible when the scanner is ready, and will trigger the scanner when clicked.
 *
 * @example
 * ```html
 * <!-- Template-driven form -->
 * <shared-scanner-button [(ngModel)]="barcodeValue"></shared-scanner-button>
 *
 * <!-- Reactive form -->
 * <shared-scanner-button formControlName="barcode"></shared-scanner-button>
 * ```
 */
@Component({
  selector: 'shared-scanner-button',
  templateUrl: './scanner-button.component.html',
  styleUrls: ['./scanner-button.component.scss'],
  changeDetection: ChangeDetectionStrategy.OnPush,
  imports: [IconButtonComponent, ScannerReadyDirective],
})
export class ScannerButtonComponent implements OnDestroy {
  #logger = logger(() => ({
    component: 'ScannerButtonComponent',
  }));

  #abortController = new AbortController();

  #scannerService = inject(ScannerService);

  /**
   * The current scanned value
   */
  scan = output<string | null>();

  /**
   * Whether the button is disabled
   */
  disabled = model<boolean>(false);

  /**
   * The size of the scanner button.
   * Accepts values defined in the `IconButtonSize` type.
   * Defaults to 'large'.
   *
   * @default 'large'
   */
  size = input<IconButtonSize>('large');

  /**
   * Opens the scanner when the button is clicked
   * The scanned value will be set to the form control if successful
   */
  async openScanner() {
    this.#logger.info('Opening scanner');
    const res = await this.#scannerService.open({
      abortSignal: this.#abortController.signal,
    });
    this.#logger.info('Scanner closed', () => ({ result: res }));
    this.scan.emit(res);
  }

  /**
   * Cleanup by aborting any in-progress scanning operations
   */
  ngOnDestroy(): void {
    this.#abortController.abort();
  }
}
