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

// 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);
      }
    }
  }),
}));

describe('BarcodeComponent', () => {
  let component: BarcodeComponent;
  let fixture: ComponentFixture<BarcodeComponent>;

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

    fixture = TestBed.createComponent(BarcodeComponent);
    component = fixture.componentInstance;
  });

  describe('Initialization', () => {
    it('should create', () => {
      fixture.componentRef.setInput('value', '123456789');
      fixture.detectChanges();

      expect(component).toBeTruthy();
    });

    it('should render an SVG element', () => {
      fixture.componentRef.setInput('value', '123456789');
      fixture.detectChanges();

      const svg = fixture.nativeElement.querySelector('svg');
      expect(svg).toBeTruthy();
      expect(svg.tagName).toBe('svg');
    });

    it('should apply the barcode directive to the SVG', () => {
      fixture.componentRef.setInput('value', '123456789');
      fixture.detectChanges();

      const svg = fixture.nativeElement.querySelector('svg[sharedBarcode]');
      expect(svg).toBeTruthy();
    });
  });

  describe('Input Bindings', () => {
    it('should pass value input to directive', () => {
      fixture.componentRef.setInput('value', 'TEST123');
      fixture.detectChanges();

      expect(component.value()).toBe('TEST123');
    });

    it('should pass format input to directive', () => {
      fixture.componentRef.setInput('value', '123');
      fixture.componentRef.setInput('format', 'CODE39');
      fixture.detectChanges();

      expect(component.format()).toBe('CODE39');
    });

    it('should pass width input to directive', () => {
      fixture.componentRef.setInput('value', '123');
      fixture.componentRef.setInput('width', 4);
      fixture.detectChanges();

      expect(component.width()).toBe(4);
    });

    it('should pass height input to directive', () => {
      fixture.componentRef.setInput('value', '123');
      fixture.componentRef.setInput('height', 200);
      fixture.detectChanges();

      expect(component.height()).toBe(200);
    });

    it('should pass displayValue input to directive', () => {
      fixture.componentRef.setInput('value', '123');
      fixture.componentRef.setInput('displayValue', false);
      fixture.detectChanges();

      expect(component.displayValue()).toBe(false);
    });

    it('should pass lineColor input to directive', () => {
      fixture.componentRef.setInput('value', '123');
      fixture.componentRef.setInput('lineColor', '#FF0000');
      fixture.detectChanges();

      expect(component.lineColor()).toBe('#FF0000');
    });

    it('should pass container background input', () => {
      fixture.componentRef.setInput('value', '123');
      fixture.componentRef.setInput('background', '#F0F0F0');
      fixture.detectChanges();

      expect(component.background()).toBe('#F0F0F0');
    });

    it('should pass svgBackground input to directive', () => {
      fixture.componentRef.setInput('value', '123');
      fixture.componentRef.setInput('svgBackground', '#FFFFFF');
      fixture.detectChanges();

      expect(component.svgBackground()).toBe('#FFFFFF');
    });

    it('should pass containerWidth input', () => {
      fixture.componentRef.setInput('value', '123');
      fixture.componentRef.setInput('containerWidth', '20rem');
      fixture.detectChanges();

      expect(component.containerWidth()).toBe('20rem');
    });

    it('should pass containerHeight input', () => {
      fixture.componentRef.setInput('value', '123');
      fixture.componentRef.setInput('containerHeight', '6rem');
      fixture.detectChanges();

      expect(component.containerHeight()).toBe('6rem');
    });

    it('should pass fontSize input to directive', () => {
      fixture.componentRef.setInput('value', '123');
      fixture.componentRef.setInput('fontSize', 24);
      fixture.detectChanges();

      expect(component.fontSize()).toBe(24);
    });

    it('should pass margin input to directive', () => {
      fixture.componentRef.setInput('value', '123');
      fixture.componentRef.setInput('margin', 15);
      fixture.detectChanges();

      expect(component.margin()).toBe(15);
    });
  });

  describe('Default Values', () => {
    it('should use default format CODE128', () => {
      fixture.componentRef.setInput('value', '123');
      fixture.detectChanges();

      expect(component.format()).toBe('CODE128');
    });

    it('should use default width 2', () => {
      fixture.componentRef.setInput('value', '123');
      fixture.detectChanges();

      expect(component.width()).toBe(2);
    });

    it('should use default height 100', () => {
      fixture.componentRef.setInput('value', '123');
      fixture.detectChanges();

      expect(component.height()).toBe(100);
    });

    it('should use default displayValue true', () => {
      fixture.componentRef.setInput('value', '123');
      fixture.detectChanges();

      expect(component.displayValue()).toBe(true);
    });

    it('should use default lineColor #000000', () => {
      fixture.componentRef.setInput('value', '123');
      fixture.detectChanges();

      expect(component.lineColor()).toBe('#000000');
    });

    it('should use default container background #ffffff', () => {
      fixture.componentRef.setInput('value', '123');
      fixture.detectChanges();

      expect(component.background()).toBe('#ffffff');
    });

    it('should use default svgBackground transparent', () => {
      fixture.componentRef.setInput('value', '123');
      fixture.detectChanges();

      expect(component.svgBackground()).toBe('transparent');
    });

    it('should use default containerWidth 12.5rem', () => {
      fixture.componentRef.setInput('value', '123');
      fixture.detectChanges();

      expect(component.containerWidth()).toBe('12.5rem');
    });

    it('should use default containerHeight 5.5rem', () => {
      fixture.componentRef.setInput('value', '123');
      fixture.detectChanges();

      expect(component.containerHeight()).toBe('5.5rem');
    });

    it('should use default fontSize 20', () => {
      fixture.componentRef.setInput('value', '123');
      fixture.detectChanges();

      expect(component.fontSize()).toBe(20);
    });

    it('should use default margin 10', () => {
      fixture.componentRef.setInput('value', '123');
      fixture.detectChanges();

      expect(component.margin()).toBe(10);
    });
  });

  describe('Host Styling', () => {
    it('should apply container width style', () => {
      fixture.componentRef.setInput('value', '123');
      fixture.componentRef.setInput('containerWidth', '25rem');
      fixture.detectChanges();

      expect(fixture.nativeElement.style.width).toBe('25rem');
    });

    it('should apply container height style', () => {
      fixture.componentRef.setInput('value', '123');
      fixture.componentRef.setInput('containerHeight', '8rem');
      fixture.detectChanges();

      expect(fixture.nativeElement.style.height).toBe('8rem');
    });

    it('should apply background color style', () => {
      fixture.componentRef.setInput('value', '123');
      fixture.componentRef.setInput('background', '#EEEEEE');
      fixture.detectChanges();

      expect(fixture.nativeElement.style.backgroundColor).toBe(
        'rgb(238, 238, 238)',
      );
    });

    it('should apply flex display style', () => {
      fixture.componentRef.setInput('value', '123');
      fixture.detectChanges();

      expect(fixture.nativeElement.style.display).toBe('flex');
    });
  });

  describe('Barcode Rendering', () => {
    it('should render barcode with custom value', () => {
      fixture.componentRef.setInput('value', '987654321');
      fixture.detectChanges();

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

    it('should update when value changes', () => {
      fixture.componentRef.setInput('value', 'INITIAL');
      fixture.detectChanges();

      fixture.componentRef.setInput('value', 'UPDATED');
      fixture.detectChanges();

      expect(component.value()).toBe('UPDATED');
    });
  });
});
