import {
  ChangeDetectionStrategy,
  Component,
  inject,
  input,
  signal,
} from '@angular/core';
import { InfoButtonComponent } from '@isa/ui/buttons';
import { Printer, PrinterType } from '../../models';
import { NgIcon, provideIcons } from '@ng-icons/core';
import { isaActionPrinter } from '@isa/icons';
import { PrintService } from '../../services';
import { logger } from '@isa/core/logging';

export type PrintFn = (printer: Printer) => PromiseLike<unknown>;

/**
 * A reusable button component that provides print functionality for the application.
 * It displays a button with a printer icon that initiates the printing process when clicked.
 *
 * The component handles the printing state and communicates with the PrintService
 * to perform printing operations with the appropriate printer type.
 *
 * @example
 * <common-print-button
 *   [printerType]="PrinterType.LABEL"
 *   [printFn]="(printer) => myPrintingAction(printer)"
 *   [directPrint]="true">
 *   Print Label
 * </common-print-button>
 */
@Component({
  selector: 'common-print-button',
  templateUrl: './print-button.component.html',
  styleUrls: ['./print-button.component.scss'],
  changeDetection: ChangeDetectionStrategy.OnPush,
  imports: [InfoButtonComponent, NgIcon],
  providers: [provideIcons({ isaActionPrinter })],
})
export class PrintButtonComponent {
  #logger = logger(() => ({ component: 'PrintButtonComponent' }));

  #printService = inject(PrintService);

  /**
   * The type of printer to use for the print operation.
   * Must be one of the values from the PrinterType enum.
   */
  printerType = input.required<PrinterType>();

  /**
   * Function that will be called to execute the actual printing logic.
   * This function should accept a Printer object and return a Promise.
   */
  printFn = input.required<PrintFn>();

  /**
   * Controls whether to print directly without showing a printer selection dialog.
   * - If true: Always prints directly without dialog.
   * - If false: Always shows the printer selection dialog.
   * - If undefined: Shows dialog only on mobile devices or when no default printer is selected.
   */
  directPrint = input<boolean | undefined>();

  /**
   * Signal that tracks the current printing state.
   * Used to manage UI state changes during the print operation.
   */
  printing = signal(false);

  /**
   * Initiates the printing process when the button is clicked.
   * Sets the printing signal to true during the operation and back to false when completed.
   * Handles any errors that occur during printing by logging them to the logger.
   *
   * @returns A promise that resolves when the print operation completes.
   */
  async print() {
    this.printing.set(true);
    try {
      await this.#printService.print({
        printerType: this.printerType(),
        printFn: this.printFn(),
        directPrint: this.directPrint(),
      });
    } catch (error) {
      this.#logger.error('Print operation failed', error as Error);
    }
    this.printing.set(false);
  }
}
