import { Component } from '@angular/core';
import { ComponentFixture, TestBed } from '@angular/core/testing';
import { beforeEach, describe, expect, it, vi } from 'vitest';
import { BarcodeDirective } from './barcode.directive';

// Mock JsBarcode
vi.mock('jsbarcode', () => ({
  default: vi.fn((element, value, options) => {
    // Simulate JsBarcode by adding a rect element to the SVG
    if (element && element.tagName === 'svg') {
      const rect = document.createElementNS(
        'http://www.w3.org/2000/svg',
        'rect',
      );
      rect.setAttribute('data-value', value);
      rect.setAttribute('data-format', options?.format || 'CODE128');
      element.appendChild(rect);

      // Call valid callback if provided
      if (options?.valid) {
        const isValid = value && value.length > 0;
        options.valid(isValid);
      }
    }
  }),
}));

@Component({
  standalone: true,
  imports: [BarcodeDirective],
  template: `
    <svg
      sharedBarcode
      [value]="barcodeValue"
      [format]="format"
      [width]="width"
      [height]="height"
      [displayValue]="displayValue"
    ></svg>
  `,
})
class TestHostComponent {
  barcodeValue = '123456789';
  format = 'CODE128';
  width = 2;
  height = 100;
  displayValue = true;
}

describe('BarcodeDirective', () => {
  let fixture: ComponentFixture<TestHostComponent>;
  let component: TestHostComponent;
  let svgElement: SVGElement;

  beforeEach(async () => {
    await TestBed.configureTestingModule({
      imports: [TestHostComponent],
    }).compileComponents();

    fixture = TestBed.createComponent(TestHostComponent);
    component = fixture.componentInstance;
    svgElement = fixture.nativeElement.querySelector('svg');
    fixture.detectChanges();
  });

  describe('Initialization', () => {
    it('should create the directive', () => {
      expect(component).toBeTruthy();
    });

    it('should apply to SVG element', () => {
      expect(svgElement).toBeTruthy();
      expect(svgElement.tagName).toBe('svg');
    });

    it('should render barcode on initialization', () => {
      // JsBarcode adds child elements to the SVG
      expect(svgElement.children.length).toBeGreaterThan(0);
    });
  });

  describe('Barcode Rendering', () => {
    it('should render barcode with default CODE128 format', () => {
      const rect = svgElement.querySelector('rect');
      expect(rect).toBeTruthy();
    });

    it('should render barcode with custom value', () => {
      component.barcodeValue = '987654321';
      fixture.detectChanges();

      // SVG should be updated with new value
      expect(svgElement.children.length).toBeGreaterThan(0);
    });

    it('should update barcode when value changes', () => {
      component.barcodeValue = 'NEWVALUE123';
      fixture.detectChanges();

      // Barcode should be re-rendered (may have different number of bars)
      expect(svgElement.children.length).toBeGreaterThan(0);
    });

    it('should render with custom width', () => {
      component.width = 4;
      fixture.detectChanges();

      expect(svgElement.children.length).toBeGreaterThan(0);
    });

    it('should render with custom height', () => {
      component.height = 200;
      fixture.detectChanges();

      const rect = svgElement.querySelector('rect');
      expect(rect).toBeTruthy();
    });

    it('should render without display value when disabled', () => {
      component.displayValue = false;
      fixture.detectChanges();

      // Check that SVG is still rendered
      expect(svgElement.children.length).toBeGreaterThan(0);
    });
  });

  describe('Input Changes', () => {
    it('should re-render when format changes', () => {
      component.format = 'CODE128';
      fixture.detectChanges();

      expect(svgElement.children.length).toBeGreaterThan(0);
    });

    it('should handle multiple rapid value changes', () => {
      component.barcodeValue = 'VALUE1';
      fixture.detectChanges();

      component.barcodeValue = 'VALUE2';
      fixture.detectChanges();

      component.barcodeValue = 'VALUE3';
      fixture.detectChanges();

      expect(svgElement.children.length).toBeGreaterThan(0);
    });
  });

  describe('Error Handling', () => {
    it('should handle empty value gracefully', () => {
      // JsBarcode should handle this or log warning
      component.barcodeValue = '';
      fixture.detectChanges();

      // Directive should not crash
      expect(component).toBeTruthy();
    });

    it('should handle very long values', () => {
      component.barcodeValue = '1'.repeat(100);
      fixture.detectChanges();

      expect(svgElement.children.length).toBeGreaterThan(0);
    });
  });

  describe('Customization Options', () => {
    it('should render with custom line color', () => {
      @Component({
        standalone: true,
        imports: [BarcodeDirective],
        template: `
          <svg sharedBarcode [value]="'123456'" [lineColor]="'#FF0000'"></svg>
        `,
      })
      class ColorTestComponent {}

      const colorFixture = TestBed.createComponent(ColorTestComponent);
      colorFixture.detectChanges();

      const svg = colorFixture.nativeElement.querySelector('svg');
      expect(svg).toBeTruthy();
      expect(svg.children.length).toBeGreaterThan(0);
    });

    it('should render with custom background', () => {
      @Component({
        standalone: true,
        imports: [BarcodeDirective],
        template: `
          <svg sharedBarcode [value]="'123456'" [background]="'#F0F0F0'"></svg>
        `,
      })
      class BackgroundTestComponent {}

      const bgFixture = TestBed.createComponent(BackgroundTestComponent);
      bgFixture.detectChanges();

      const svg = bgFixture.nativeElement.querySelector('svg');
      expect(svg).toBeTruthy();
    });

    it('should render with transparent background by default', () => {
      @Component({
        standalone: true,
        imports: [BarcodeDirective],
        template: ` <svg sharedBarcode [value]="'123456'"></svg> `,
      })
      class DefaultBackgroundTestComponent {}

      const bgFixture = TestBed.createComponent(DefaultBackgroundTestComponent);
      bgFixture.detectChanges();

      const svg = bgFixture.nativeElement.querySelector('svg');
      expect(svg).toBeTruthy();
    });

    it('should render with custom font size', () => {
      @Component({
        standalone: true,
        imports: [BarcodeDirective],
        template: `
          <svg sharedBarcode [value]="'123456'" [fontSize]="30"></svg>
        `,
      })
      class FontSizeTestComponent {}

      const fontFixture = TestBed.createComponent(FontSizeTestComponent);
      fontFixture.detectChanges();

      const svg = fontFixture.nativeElement.querySelector('svg');
      expect(svg).toBeTruthy();
    });

    it('should render with custom margin', () => {
      @Component({
        standalone: true,
        imports: [BarcodeDirective],
        template: `
          <svg sharedBarcode [value]="'123456'" [margin]="20"></svg>
        `,
      })
      class MarginTestComponent {}

      const marginFixture = TestBed.createComponent(MarginTestComponent);
      marginFixture.detectChanges();

      const svg = marginFixture.nativeElement.querySelector('svg');
      expect(svg).toBeTruthy();
    });
  });
});
