import { ComponentFixture, TestBed } from '@angular/core/testing';
import { ModalComponent } from './modal';
import { By } from '@angular/platform-browser';

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

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

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

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

  describe('Input Properties', () => {
    it('should have default values', () => {
      expect(component.isOpen).toBe(false);
      expect(component.title).toBe('');
      expect(component.size).toBe('md');
    });

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

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

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

  describe('Template Rendering', () => {
    it('should not render modal when isOpen is false', () => {
      component.isOpen = false;
      fixture.detectChanges();
      const modal = fixture.debugElement.query(By.css('.modal-overlay'));
      expect(modal).toBeNull();
    });

    it('should render modal when isOpen is true', () => {
      component.isOpen = true;
      fixture.detectChanges();
      const modal = fixture.debugElement.query(By.css('.modal-overlay'));
      expect(modal).toBeTruthy();
    });

    it('should render modal content', () => {
      component.isOpen = true;
      fixture.detectChanges();
      const content = fixture.debugElement.query(By.css('.modal-content'));
      expect(content).toBeTruthy();
    });

    it('should render modal body', () => {
      component.isOpen = true;
      fixture.detectChanges();
      const body = fixture.debugElement.query(By.css('.modal-body'));
      expect(body).toBeTruthy();
    });

    it('should render projected content', () => {
      component.isOpen = true;
      fixture.nativeElement.innerHTML = `<ccl-modal [isOpen]="true">Test Content</ccl-modal>`;
      fixture.detectChanges();
      expect(fixture.nativeElement.textContent).toContain('Test Content');
    });
  });

  describe('Title Rendering', () => {
    it('should render title when provided', () => {
      component.isOpen = true;
      component.title = 'Test Modal';
      fixture.detectChanges();
      const title = fixture.debugElement.query(By.css('.modal-header h2'));
      expect(title.nativeElement.textContent).toContain('Test Modal');
    });

    it('should not render header when title is empty', () => {
      component.isOpen = true;
      component.title = '';
      fixture.detectChanges();
      const header = fixture.debugElement.query(By.css('.modal-header'));
      expect(header).toBeNull();
    });

    it('should not render header when title is not provided', () => {
      component.isOpen = true;
      component.title = undefined as any;
      fixture.detectChanges();
      const header = fixture.debugElement.query(By.css('.modal-header'));
      expect(header).toBeNull();
    });

    it('should render close button when title is provided', () => {
      component.isOpen = true;
      component.title = 'Test Modal';
      fixture.detectChanges();
      const closeButton = fixture.debugElement.query(By.css('.modal-close'));
      expect(closeButton).toBeTruthy();
    });

    it('should not render close button when title is not provided', () => {
      component.isOpen = true;
      component.title = '';
      fixture.detectChanges();
      const closeButton = fixture.debugElement.query(By.css('.modal-close'));
      expect(closeButton).toBeNull();
    });
  });

  describe('Size Variants', () => {
    it('should apply medium size by default', () => {
      component.isOpen = true;
      fixture.detectChanges();
      const content = fixture.debugElement.query(By.css('.modal-content'));
      expect(content.nativeElement.classList).toContain('modal-content--md');
    });

    it('should apply small size when size="sm"', () => {
      component.isOpen = true;
      component.size = 'sm';
      fixture.detectChanges();
      const content = fixture.debugElement.query(By.css('.modal-content'));
      expect(content.nativeElement.classList).toContain('modal-content--sm');
    });

    it('should apply large size when size="lg"', () => {
      component.isOpen = true;
      component.size = 'lg';
      fixture.detectChanges();
      const content = fixture.debugElement.query(By.css('.modal-content'));
      expect(content.nativeElement.classList).toContain('modal-content--lg');
    });
  });

  describe('Close Functionality', () => {
    it('should emit closed event when close is called', () => {
      spyOn(component.closed, 'emit');
      component.close();
      expect(component.closed.emit).toHaveBeenCalled();
    });

    it('should call close when close button is clicked', () => {
      component.isOpen = true;
      component.title = 'Test Modal';
      spyOn(component, 'close');
      fixture.detectChanges();
      const closeButton = fixture.debugElement.query(By.css('.modal-close'));
      closeButton.nativeElement.click();
      expect(component.close).toHaveBeenCalled();
    });

    it('should call close when overlay is clicked', () => {
      component.isOpen = true;
      spyOn(component, 'close');
      fixture.detectChanges();
      const overlay = fixture.debugElement.query(By.css('.modal-overlay'));
      const mockEvent = { target: overlay.nativeElement, currentTarget: overlay.nativeElement } as MouseEvent;
      component.onOverlayClick(mockEvent);
      expect(component.close).toHaveBeenCalled();
    });

    it('should not call close when content is clicked', () => {
      component.isOpen = true;
      spyOn(component, 'close');
      fixture.detectChanges();
      const content = fixture.debugElement.query(By.css('.modal-content'));
      const overlay = fixture.debugElement.query(By.css('.modal-overlay'));
      // Simulate clicking on content (target) while overlay is currentTarget
      const mockEvent = { target: content.nativeElement, currentTarget: overlay.nativeElement } as MouseEvent;
      component.onOverlayClick(mockEvent);
      // The onOverlayClick method checks if target === currentTarget, so this should not call close
      expect(component.close).not.toHaveBeenCalled();
    });
  });

  describe('Keyboard Events', () => {
    it('should call close when Escape key is pressed on overlay', () => {
      component.isOpen = true;
      spyOn(component, 'close');
      fixture.detectChanges();
      const overlay = fixture.debugElement.query(By.css('.modal-overlay'));
      overlay.triggerEventHandler('keyup.escape', null);
      expect(component.close).toHaveBeenCalled();
    });

    it('should call close when Escape key is pressed on content', () => {
      component.isOpen = true;
      spyOn(component, 'close');
      fixture.detectChanges();
      const content = fixture.debugElement.query(By.css('.modal-content'));
      content.triggerEventHandler('keyup.escape', null);
      expect(component.close).toHaveBeenCalled();
    });

    it('should call close when Enter key is pressed on close button', () => {
      component.isOpen = true;
      component.title = 'Test Modal';
      spyOn(component, 'close');
      fixture.detectChanges();
      const closeButton = fixture.debugElement.query(By.css('.modal-close'));
      closeButton.triggerEventHandler('keyup.enter', null);
      expect(component.close).toHaveBeenCalled();
    });

    it('should call close when Space key is pressed on close button', () => {
      component.isOpen = true;
      component.title = 'Test Modal';
      spyOn(component, 'close');
      fixture.detectChanges();
      const closeButton = fixture.debugElement.query(By.css('.modal-close'));
      closeButton.triggerEventHandler('keyup.space', null);
      expect(component.close).toHaveBeenCalled();
    });
  });

  describe('Accessibility', () => {
    it('should have proper ARIA attributes when open', () => {
      component.isOpen = true;
      component.title = 'Test Modal';
      fixture.detectChanges();
      const overlay = fixture.debugElement.query(By.css('.modal-overlay'));
      expect(overlay.nativeElement.getAttribute('role')).toBe('dialog');
      expect(overlay.nativeElement.getAttribute('aria-modal')).toBe('true');
      expect(overlay.nativeElement.getAttribute('aria-labelledby')).toMatch(/modal-\w+-title/);
    });

    it('should have proper ARIA attributes when no title', () => {
      component.isOpen = true;
      component.title = '';
      fixture.detectChanges();
      const overlay = fixture.debugElement.query(By.css('.modal-overlay'));
      expect(overlay.nativeElement.getAttribute('role')).toBe('dialog');
      expect(overlay.nativeElement.getAttribute('aria-modal')).toBe('true');
      expect(overlay.nativeElement.getAttribute('aria-labelledby')).toBeNull();
    });

    it('should have proper title ID', () => {
      component.isOpen = true;
      component.title = 'Test Modal';
      fixture.detectChanges();
      const title = fixture.debugElement.query(By.css('.modal-header h2'));
      expect(title.nativeElement.getAttribute('id')).toMatch(/modal-\w+-title/);
    });

    it('should have proper close button ARIA label', () => {
      component.isOpen = true;
      component.title = 'Test Modal';
      fixture.detectChanges();
      const closeButton = fixture.debugElement.query(By.css('.modal-close'));
      expect(closeButton.nativeElement.getAttribute('aria-label')).toBe('Close modal');
    });

    it('should be focusable when open', () => {
      component.isOpen = true;
      fixture.detectChanges();
      const overlay = fixture.debugElement.query(By.css('.modal-overlay'));
      const content = fixture.debugElement.query(By.css('.modal-content'));
      expect(overlay.nativeElement.getAttribute('tabindex')).toBe('0');
      expect(content.nativeElement.getAttribute('tabindex')).toBe('0');
    });
  });

  describe('Event Handling', () => {
    it('should stop propagation when content is clicked', () => {
      component.isOpen = true;
      fixture.detectChanges();
      const content = fixture.debugElement.query(By.css('.modal-content'));
      const mockEvent = { stopPropagation: jasmine.createSpy('stopPropagation') } as any;
      content.triggerEventHandler('click', mockEvent);
      expect(mockEvent.stopPropagation).toHaveBeenCalled();
    });
  });
});
