import {
  Directive,
  ElementRef,
  effect,
  inject,
  input,
  type OnDestroy,
} from '@angular/core';
import JsBarcode from 'jsbarcode';
import { logger } from '@isa/core/logging';

/**
 * Directive for rendering Code 128 barcodes on SVG elements using JsBarcode.
 *
 * @example
 * ```html
 * <svg sharedBarcode [value]="'123456789'" [width]="2" [height]="100"></svg>
 * ```
 */
@Directive({
  selector: 'svg[sharedBarcode]',
  standalone: true,
})
export class BarcodeDirective implements OnDestroy {
  readonly #elementRef = inject(ElementRef<SVGElement>);
  readonly #logger = logger({ directive: 'BarcodeDirective' });

  /**
   * The barcode value to encode (required)
   */
  value = input.required<string>();

  /**
   * Barcode format (default: CODE128)
   */
  format = input<string>('CODE128');

  /**
   * Width of a single bar in pixels (default: 2)
   */
  width = input<number>(2);

  /**
   * Height of the barcode in pixels (default: 100)
   */
  height = input<number>(100);

  /**
   * Whether to display the human-readable value below the barcode (default: true)
   */
  displayValue = input<boolean>(true);

  /**
   * Color of the barcode bars and text (default: #000000)
   */
  lineColor = input<string>('#000000');

  /**
   * Background color of the SVG barcode itself (default: transparent)
   */
  background = input<string>('transparent');

  /**
   * Font size for the human-readable text (default: 20)
   */
  fontSize = input<number>(20);

  /**
   * Margin around the barcode in pixels (default: 10)
   */
  margin = input<number>(10);

  constructor() {
    // Re-render barcode whenever any input changes
    effect(() => {
      this.#renderBarcode();
    });
  }

  ngOnDestroy(): void {
    this.#logger.debug('Directive destroyed', () => ({
      value: this.value(),
    }));
  }

  #renderBarcode(): void {
    const element = this.#elementRef.nativeElement;
    const value = this.value();

    try {
      JsBarcode(element, value, {
        format: this.format(),
        width: this.width(),
        height: this.height(),
        displayValue: this.displayValue(),
        lineColor: this.lineColor(),
        background: this.background(),
        fontSize: this.fontSize(),
        margin: this.margin(),
        valid: (isValid: boolean) => {
          if (!isValid) {
            this.#logger.warn('Invalid barcode data', () => ({
              value,
              format: this.format(),
            }));
          }
        },
      });

      this.#logger.debug('Barcode rendered', () => ({
        value,
        format: this.format(),
      }));
    } catch (error) {
      this.#logger.error('Failed to render barcode', error as Error, () => ({
        value,
        format: this.format(),
      }));
    }
  }
}
