import { ComponentFixture, TestBed } from '@angular/core/testing';
import { By } from '@angular/platform-browser';
import { BadgeComponent, BadgeVariant, BadgeSize } from './badge';
import { FormsModule, ReactiveFormsModule, FormControl } from '@angular/forms';

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

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

    fixture = TestBed.createComponent(BadgeComponent);
    component = fixture.componentInstance;
    fixture.detectChanges();
  });

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

  describe('Input Properties', () => {
    it('should have default values', () => {
      expect(component.variant).toBe('default');
      expect(component.label).toBe('');
      expect(component.icon).toBe('');
      expect(component.dismissible).toBe(false);
      expect(component.count).toBe(null);
      expect(component.clickable).toBe(false);
      expect(component.size).toBe('md');
      expect(component.customColor).toBe('');
      expect(component.disabled).toBe(false);
    });

    it('should accept variant input', () => {
      const variants: BadgeVariant[] = ['default', 'success', 'error', 'warning', 'info', 'custom'];
      variants.forEach(variant => {
        component.variant = variant;
        fixture.detectChanges();
        expect(component.variant).toBe(variant);
      });
    });

    it('should accept size input', () => {
      const sizes: BadgeSize[] = ['sm', 'md', 'lg'];
      sizes.forEach(size => {
        component.size = size;
        fixture.detectChanges();
        expect(component.size).toBe(size);
      });
    });

    it('should accept label input', () => {
      component.label = 'Test Label';
      fixture.detectChanges();
      expect(component.label).toBe('Test Label');
    });

    it('should accept icon input', () => {
      component.icon = '★';
      fixture.detectChanges();
      expect(component.icon).toBe('★');
    });

    it('should accept dismissible input', () => {
      component.dismissible = true;
      fixture.detectChanges();
      expect(component.dismissible).toBe(true);
    });

    it('should accept count input', () => {
      component.count = 5;
      fixture.detectChanges();
      expect(component.count).toBe(5);
    });

    it('should accept clickable input', () => {
      component.clickable = true;
      fixture.detectChanges();
      expect(component.clickable).toBe(true);
    });

    it('should accept customColor input', () => {
      component.customColor = '#ff6b6b';
      fixture.detectChanges();
      expect(component.customColor).toBe('#ff6b6b');
    });

    it('should accept disabled input', () => {
      component.disabled = true;
      fixture.detectChanges();
      expect(component.disabled).toBe(true);
    });
  });

  describe('Template Rendering', () => {
    it('should render badge element', () => {
      const badgeElement = fixture.debugElement.query(By.css('.ccl-badge'));
      expect(badgeElement).toBeTruthy();
    });

    it('should apply variant class', () => {
      component.variant = 'success';
      fixture.detectChanges();
      const badgeElement = fixture.debugElement.query(By.css('.ccl-badge--success'));
      expect(badgeElement).toBeTruthy();
    });

    it('should apply size class', () => {
      component.size = 'lg';
      fixture.detectChanges();
      const badgeElement = fixture.debugElement.query(By.css('.ccl-badge--lg'));
      expect(badgeElement).toBeTruthy();
    });

    it('should apply clickable class when clickable is true', () => {
      component.clickable = true;
      fixture.detectChanges();
      const badgeElement = fixture.debugElement.query(By.css('.ccl-badge--clickable'));
      expect(badgeElement).toBeTruthy();
    });

    it('should apply dismissible class when dismissible is true', () => {
      component.dismissible = true;
      fixture.detectChanges();
      const badgeElement = fixture.debugElement.query(By.css('.ccl-badge--dismissible'));
      expect(badgeElement).toBeTruthy();
    });

    it('should apply count class when count is provided', () => {
      component.count = 5;
      fixture.detectChanges();
      const badgeElement = fixture.debugElement.query(By.css('.ccl-badge--count'));
      expect(badgeElement).toBeTruthy();
    });

    it('should apply disabled class when disabled is true', () => {
      component.disabled = true;
      fixture.detectChanges();
      const badgeElement = fixture.debugElement.query(By.css('.ccl-badge--disabled'));
      expect(badgeElement).toBeTruthy();
    });

    it('should render label text', () => {
      component.label = 'Test Badge';
      fixture.detectChanges();
      const contentElement = fixture.debugElement.query(By.css('.ccl-badge__content'));
      expect(contentElement.nativeElement.textContent.trim()).toBe('Test Badge');
    });

    it('should render count when count is provided', () => {
      component.count = 42;
      fixture.detectChanges();
      const contentElement = fixture.debugElement.query(By.css('.ccl-badge__content'));
      expect(contentElement.nativeElement.textContent.trim()).toBe('42');
    });

    it('should render 999+ for large counts', () => {
      component.count = 1500;
      fixture.detectChanges();
      const contentElement = fixture.debugElement.query(By.css('.ccl-badge__content'));
      expect(contentElement.nativeElement.textContent.trim()).toBe('999+');
    });

    it('should render icon when provided', () => {
      component.icon = '★';
      component.label = 'Star';
      fixture.detectChanges();
      const iconElement = fixture.debugElement.query(By.css('.ccl-badge__icon'));
      expect(iconElement).toBeTruthy();
      expect(iconElement.nativeElement.textContent.trim()).toBe('★');
    });

    it('should render dismiss button when dismissible is true', () => {
      component.dismissible = true;
      component.label = 'Dismissible Badge';
      fixture.detectChanges();
      const dismissButton = fixture.debugElement.query(By.css('.ccl-badge__dismiss'));
      expect(dismissButton).toBeTruthy();
    });

    it('should not render dismiss button when dismissible is false', () => {
      component.dismissible = false;
      fixture.detectChanges();
      const dismissButton = fixture.debugElement.query(By.css('.ccl-badge__dismiss'));
      expect(dismissButton).toBeFalsy();
    });
  });

  describe('Interactive Behavior', () => {
    it('should emit onClick when clicked and clickable is true', () => {
      component.clickable = true;
      spyOn(component.onClick, 'emit');
      fixture.detectChanges();
      
      const badgeElement = fixture.debugElement.query(By.css('.ccl-badge'));
      badgeElement.nativeElement.click();
      
      expect(component.onClick.emit).toHaveBeenCalled();
    });

    it('should not emit onClick when clicked and clickable is false', () => {
      component.clickable = false;
      spyOn(component.onClick, 'emit');
      fixture.detectChanges();
      
      const badgeElement = fixture.debugElement.query(By.css('.ccl-badge'));
      badgeElement.nativeElement.click();
      
      expect(component.onClick.emit).not.toHaveBeenCalled();
    });

    it('should not emit onClick when disabled', () => {
      component.clickable = true;
      component.disabled = true;
      spyOn(component.onClick, 'emit');
      fixture.detectChanges();
      
      const badgeElement = fixture.debugElement.query(By.css('.ccl-badge'));
      badgeElement.nativeElement.click();
      
      expect(component.onClick.emit).not.toHaveBeenCalled();
    });

    it('should emit onDismiss when dismiss button is clicked', () => {
      component.dismissible = true;
      component.label = 'Test Badge';
      spyOn(component.onDismiss, 'emit');
      fixture.detectChanges();
      
      const dismissButton = fixture.debugElement.query(By.css('.ccl-badge__dismiss'));
      dismissButton.nativeElement.click();
      
      expect(component.onDismiss.emit).toHaveBeenCalled();
    });

    it('should not emit onDismiss when disabled', () => {
      component.dismissible = true;
      component.disabled = true;
      spyOn(component.onDismiss, 'emit');
      fixture.detectChanges();
      
      const dismissButton = fixture.debugElement.query(By.css('.ccl-badge__dismiss'));
      dismissButton.nativeElement.click();
      
      expect(component.onDismiss.emit).not.toHaveBeenCalled();
    });
  });

  describe('Keyboard Navigation', () => {
    it('should handle Enter key when clickable', () => {
      component.clickable = true;
      spyOn(component, 'onBadgeClick');
      fixture.detectChanges();
      
      const badgeElement = fixture.debugElement.query(By.css('.ccl-badge'));
      badgeElement.nativeElement.dispatchEvent(new KeyboardEvent('keydown', { key: 'Enter' }));
      
      expect(component.onBadgeClick).toHaveBeenCalled();
    });

    it('should handle Space key when clickable', () => {
      component.clickable = true;
      spyOn(component, 'onBadgeClick');
      fixture.detectChanges();
      
      const badgeElement = fixture.debugElement.query(By.css('.ccl-badge'));
      badgeElement.nativeElement.dispatchEvent(new KeyboardEvent('keydown', { key: ' ' }));
      
      expect(component.onBadgeClick).toHaveBeenCalled();
    });

    it('should handle Enter key on dismiss button', () => {
      component.dismissible = true;
      component.label = 'Test Badge';
      spyOn(component, 'onDismissClick');
      fixture.detectChanges();
      
      const dismissButton = fixture.debugElement.query(By.css('.ccl-badge__dismiss'));
      dismissButton.nativeElement.dispatchEvent(new KeyboardEvent('keydown', { key: 'Enter' }));
      
      expect(component.onDismissClick).toHaveBeenCalled();
    });

    it('should handle Space key on dismiss button', () => {
      component.dismissible = true;
      component.label = 'Test Badge';
      spyOn(component, 'onDismissClick');
      fixture.detectChanges();
      
      const dismissButton = fixture.debugElement.query(By.css('.ccl-badge__dismiss'));
      dismissButton.nativeElement.dispatchEvent(new KeyboardEvent('keydown', { key: ' ' }));
      
      expect(component.onDismissClick).toHaveBeenCalled();
    });
  });

  describe('Accessibility', () => {
    it('should have correct role when clickable', () => {
      component.clickable = true;
      fixture.detectChanges();
      
      const badgeElement = fixture.debugElement.query(By.css('.ccl-badge'));
      expect(badgeElement.nativeElement.getAttribute('role')).toBe('button');
    });

    it('should have correct role when dismissible', () => {
      component.dismissible = true;
      fixture.detectChanges();
      
      const badgeElement = fixture.debugElement.query(By.css('.ccl-badge'));
      expect(badgeElement.nativeElement.getAttribute('role')).toBe('button');
    });

    it('should have status role when not interactive', () => {
      component.clickable = false;
      component.dismissible = false;
      fixture.detectChanges();
      
      const badgeElement = fixture.debugElement.query(By.css('.ccl-badge'));
      expect(badgeElement.nativeElement.getAttribute('role')).toBe('status');
    });

    it('should have correct tabindex when interactive', () => {
      component.clickable = true;
      fixture.detectChanges();
      
      const badgeElement = fixture.debugElement.query(By.css('.ccl-badge'));
      expect(badgeElement.nativeElement.getAttribute('tabindex')).toBe('0');
    });

    it('should have correct tabindex when not interactive', () => {
      component.clickable = false;
      component.dismissible = false;
      fixture.detectChanges();
      
      const badgeElement = fixture.debugElement.query(By.css('.ccl-badge'));
      expect(badgeElement.nativeElement.getAttribute('tabindex')).toBe('-1');
    });

    it('should have correct aria-label for count badge', () => {
      component.count = 5;
      fixture.detectChanges();
      
      const badgeElement = fixture.debugElement.query(By.css('.ccl-badge'));
      expect(badgeElement.nativeElement.getAttribute('aria-label')).toBe('Count: 5');
    });

    it('should have correct aria-label for variant badge', () => {
      component.label = 'Active';
      component.variant = 'success';
      fixture.detectChanges();
      
      const badgeElement = fixture.debugElement.query(By.css('.ccl-badge'));
      expect(badgeElement.nativeElement.getAttribute('aria-label')).toBe('Active, success badge');
    });

    it('should have correct aria-label for dismiss button', () => {
      component.dismissible = true;
      component.label = 'Beta Feature';
      fixture.detectChanges();
      
      const dismissButton = fixture.debugElement.query(By.css('.ccl-badge__dismiss'));
      expect(dismissButton.nativeElement.getAttribute('aria-label')).toBe('Remove Beta Feature');
    });
  });

  describe('Custom Color', () => {
    it('should apply custom background color', () => {
      component.variant = 'custom';
      component.customColor = '#ff6b6b';
      fixture.detectChanges();
      
      const badgeElement = fixture.debugElement.query(By.css('.ccl-badge'));
      expect(badgeElement.nativeElement.style.backgroundColor).toBe('rgb(255, 107, 107)');
    });

    it('should apply white text color for custom variant', () => {
      component.variant = 'custom';
      component.customColor = '#ff6b6b';
      fixture.detectChanges();
      
      const badgeElement = fixture.debugElement.query(By.css('.ccl-badge'));
      expect(badgeElement.nativeElement.style.color).toBe('white');
    });
  });

  describe('ControlValueAccessor', () => {
    it('should implement ControlValueAccessor', () => {
      expect(component.writeValue).toBeDefined();
      expect(component.registerOnChange).toBeDefined();
      expect(component.registerOnTouched).toBeDefined();
      expect(component.setDisabledState).toBeDefined();
    });

    it('should register onChange callback', () => {
      const onChangeSpy = jasmine.createSpy('onChange');
      component.registerOnChange(onChangeSpy);
      
      // Trigger a click event that should call onChange
      component.clickable = true;
      component.onBadgeClick();
      
      expect(onChangeSpy).toHaveBeenCalled();
    });

    it('should register onTouched callback', () => {
      const onTouchedSpy = jasmine.createSpy('onTouched');
      component.registerOnTouched(onTouchedSpy);
      
      // Trigger a click event that should call onTouched
      component.clickable = true;
      component.onBadgeClick();
      
      expect(onTouchedSpy).toHaveBeenCalled();
    });

    it('should set disabled state', () => {
      component.setDisabledState(true);
      expect(component.disabled).toBe(true);
    });
  });

  describe('Display Text Logic', () => {
    it('should display count when count is provided', () => {
      component.count = 42;
      fixture.detectChanges();
      expect(component.displayText).toBe('42');
    });

    it('should display label when count is null', () => {
      component.count = null;
      component.label = 'Test Label';
      fixture.detectChanges();
      expect(component.displayText).toBe('Test Label');
    });

    it('should display 999+ for large counts', () => {
      component.count = 1500;
      fixture.detectChanges();
      expect(component.displayText).toBe('999+');
    });
  });

  describe('Interactive State Logic', () => {
    it('should be interactive when clickable is true', () => {
      component.clickable = true;
      expect(component.isInteractive).toBe(true);
    });

    it('should be interactive when dismissible is true', () => {
      component.dismissible = true;
      expect(component.isInteractive).toBe(true);
    });

    it('should not be interactive when neither clickable nor dismissible', () => {
      component.clickable = false;
      component.dismissible = false;
      expect(component.isInteractive).toBe(false);
    });
  });
});
