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


import { ButtonComponent } from '../button/button';
import { InputComponent } from '../input/input';
import { ModalComponent } from '../modal/modal';
import { ToastComponent } from '../toast/toast';
import { LoadingComponent } from '../loading/loading';

// Test host component for integration testing
@Component({
  template: `
    <div>
      <ccl-button 
        [ariaLabel]="buttonAriaLabel"
        [ariaDescribedBy]="buttonDescribedBy"
        [ariaExpanded]="buttonExpanded"
        [ariaPressed]="buttonPressed"
        [disabled]="buttonDisabled"
        (clicked)="onButtonClick()">
        Test Button
      </ccl-button>

      <ccl-input 
        [label]="inputLabel"
        [ariaLabel]="inputAriaLabel"
        [ariaDescribedBy]="inputDescribedBy"
        [required]="inputRequired"
        [error]="inputError"
        [errorMessage]="inputErrorMessage"
        [helperText]="inputHelperText">
      </ccl-input>

      <ccl-modal 
        [isOpen]="modalOpen"
        [title]="modalTitle"
        [ariaLabel]="modalAriaLabel"
        (closed)="onModalClosed()">
        <p>Modal content</p>
      </ccl-modal>

      <ccl-toast 
        [variant]="toastVariant"
        [message]="toastMessage"
        [title]="toastTitle"
        [role]="toastRole"
        [ariaLive]="toastAriaLive"
        [dismissible]="toastDismissible">
      </ccl-toast>

      <ccl-loading 
        [variant]="loadingVariant"
        [label]="loadingLabel">
      </ccl-loading>

      <div id="button-description">Button description</div>
      <div id="input-description">Input description</div>
    </div>
  `,
  standalone: true,
  imports: [
    ButtonComponent,
    InputComponent,
    ModalComponent,
    ToastComponent,
    LoadingComponent
]
})
class TestHostComponent {
  buttonAriaLabel = 'Test button';
  buttonDescribedBy = 'button-description';
  buttonExpanded = false;
  buttonPressed = false;
  buttonDisabled = false;

  inputLabel = 'Test input';
  inputAriaLabel = 'Test input field';
  inputDescribedBy = 'input-description';
  inputRequired = true;
  inputError = false;
  inputErrorMessage = 'Error message';
  inputHelperText = 'Helper text';

  modalOpen = false;
  modalTitle = 'Test modal';
  modalAriaLabel = 'Test modal dialog';

  toastVariant = 'info';
  toastMessage = 'Test message';
  toastTitle = 'Test title';
  toastRole = 'status';
  toastAriaLive = 'polite';
  toastDismissible = true;

  loadingVariant = 'spinner';
  loadingLabel = 'Loading...';

  onButtonClick() {}
  onModalClosed() {}
}

describe('Accessibility Integration Tests', () => {
  let component: TestHostComponent;
  let fixture: ComponentFixture<TestHostComponent>;

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

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

  describe('Button Accessibility', () => {
    it('should have proper ARIA attributes', () => {
      const button = fixture.debugElement.query(By.css('ccl-button button'));
      
      expect(button.nativeElement.getAttribute('aria-label')).toBe('Test button');
      expect(button.nativeElement.getAttribute('aria-describedby')).toBe('button-description');
      expect(button.nativeElement.getAttribute('aria-expanded')).toBe('false');
      expect(button.nativeElement.getAttribute('aria-pressed')).toBe('false');
      expect(button.nativeElement.getAttribute('aria-disabled')).toBe('false');
    });

    it('should handle keyboard activation', () => {
      const button = fixture.debugElement.query(By.css('ccl-button button'));
      const clickSpy = spyOn(component, 'onButtonClick');
      
      // Test Enter key
      button.nativeElement.dispatchEvent(new KeyboardEvent('keydown', { key: 'Enter' }));
      expect(clickSpy).toHaveBeenCalled();
      
      // Test Space key
      clickSpy.calls.reset();
      button.nativeElement.dispatchEvent(new KeyboardEvent('keydown', { key: ' ' }));
      expect(clickSpy).toHaveBeenCalled();
    });

    it('should have visible focus indicator', () => {
      const button = fixture.debugElement.query(By.css('ccl-button button'));
      const styles = getComputedStyle(button.nativeElement);
      
      // Check that focus-visible styles are defined
      expect(button.nativeElement.classList.contains('ccl-btn')).toBe(true);
    });

    it('should be disabled when disabled prop is true', () => {
      component.buttonDisabled = true;
      fixture.detectChanges();
      
      const button = fixture.debugElement.query(By.css('ccl-button button'));
      expect(button.nativeElement.disabled).toBe(true);
      expect(button.nativeElement.getAttribute('aria-disabled')).toBe('true');
    });
  });

  describe('Input Accessibility', () => {
    it('should have proper label association', () => {
      const label = fixture.debugElement.query(By.css('ccl-input label'));
      const input = fixture.debugElement.query(By.css('ccl-input input'));
      
      expect(label.nativeElement.getAttribute('for')).toBe(input.nativeElement.id);
      expect(input.nativeElement.getAttribute('aria-label')).toBe('Test input field');
    });

    it('should have proper ARIA attributes', () => {
      const input = fixture.debugElement.query(By.css('ccl-input input'));
      
      expect(input.nativeElement.getAttribute('aria-describedby')).toContain('input-description');
      expect(input.nativeElement.getAttribute('aria-required')).toBe('true');
      expect(input.nativeElement.getAttribute('aria-invalid')).toBe('false');
    });

    it('should show required indicator', () => {
      const label = fixture.debugElement.query(By.css('ccl-input label'));
      const requiredSpan = label.nativeElement.querySelector('.ccl-input__required');
      
      expect(requiredSpan).toBeTruthy();
      expect(requiredSpan.textContent).toBe('*');
      expect(requiredSpan.getAttribute('aria-label')).toBe('required');
    });

    it('should show error message with proper role', () => {
      component.inputError = true;
      fixture.detectChanges();
      
      const errorMessage = fixture.debugElement.query(By.css('ccl-input .ccl-input__error'));
      expect(errorMessage.nativeElement.getAttribute('role')).toBe('alert');
      expect(errorMessage.nativeElement.textContent.trim()).toBe('Error message');
    });

    it('should have visible focus indicator', () => {
      const input = fixture.debugElement.query(By.css('ccl-input input'));
      const styles = getComputedStyle(input.nativeElement);
      
      // Check that focus-visible styles are defined
      expect(input.nativeElement.classList.contains('ccl-input')).toBe(true);
    });
  });

  describe('Modal Accessibility', () => {
    beforeEach(() => {
      component.modalOpen = true;
      fixture.detectChanges();
    });

    it('should have proper ARIA attributes when open', () => {
      const modal = fixture.debugElement.query(By.css('ccl-modal .modal-overlay'));
      
      expect(modal.nativeElement.getAttribute('role')).toBe('dialog');
      expect(modal.nativeElement.getAttribute('aria-modal')).toBe('true');
      expect(modal.nativeElement.getAttribute('aria-labelledby')).toBeTruthy();
    });

    it('should have proper title association', () => {
      const modal = fixture.debugElement.query(By.css('ccl-modal .modal-overlay'));
      const title = fixture.debugElement.query(By.css('ccl-modal h2'));
      
      const labelledBy = modal.nativeElement.getAttribute('aria-labelledby');
      expect(title.nativeElement.id).toBe(labelledBy);
    });

    it('should have proper close button', () => {
      const closeButton = fixture.debugElement.query(By.css('ccl-modal .modal-close'));
      
      expect(closeButton.nativeElement.getAttribute('aria-label')).toBe('Close modal');
    });

    it('should close on Escape key', () => {
      const modal = fixture.debugElement.query(By.css('ccl-modal .modal-overlay'));
      const closeSpy = spyOn(component, 'onModalClosed');
      
      modal.nativeElement.dispatchEvent(new KeyboardEvent('keydown', { key: 'Escape' }));
      expect(closeSpy).toHaveBeenCalled();
    });

    it('should not have ARIA attributes when closed', () => {
      component.modalOpen = false;
      fixture.detectChanges();
      
      const modal = fixture.debugElement.query(By.css('ccl-modal .modal-overlay'));
      expect(modal).toBeFalsy();
    });
  });

  describe('Toast Accessibility', () => {
    it('should have proper ARIA attributes', () => {
      const toast = fixture.debugElement.query(By.css('ccl-toast > div'));
      
      expect(toast.nativeElement.getAttribute('role')).toBe('status');
      expect(toast.nativeElement.getAttribute('aria-live')).toBe('polite');
    });

    it('should have proper title association when title is provided', () => {
      const toast = fixture.debugElement.query(By.css('ccl-toast > div'));
      const title = fixture.debugElement.query(By.css('ccl-toast .ccl-toast__title'));
      
      const labelledBy = toast.nativeElement.getAttribute('aria-labelledby');
      expect(title.nativeElement.id).toBe(labelledBy);
    });

    it('should have proper close button', () => {
      const closeButton = fixture.debugElement.query(By.css('ccl-toast .ccl-toast__close'));
      
      expect(closeButton.nativeElement.getAttribute('aria-label')).toBe('Close notification');
    });

    it('should hide decorative elements from screen readers', () => {
      const icon = fixture.debugElement.query(By.css('ccl-toast .ccl-toast__icon'));
      const progress = fixture.debugElement.query(By.css('ccl-toast .ccl-toast__progress'));
      
      expect(icon.nativeElement.getAttribute('aria-hidden')).toBe('true');
      expect(progress.nativeElement.getAttribute('aria-hidden')).toBe('true');
    });

    it('should support alert role for urgent messages', () => {
      component.toastRole = 'alert';
      component.toastAriaLive = 'assertive';
      fixture.detectChanges();
      
      const toast = fixture.debugElement.query(By.css('ccl-toast > div'));
      expect(toast.nativeElement.getAttribute('role')).toBe('alert');
      expect(toast.nativeElement.getAttribute('aria-live')).toBe('assertive');
    });
  });

  describe('Loading Accessibility', () => {
    it('should have proper ARIA attributes', () => {
      const loading = fixture.debugElement.query(By.css('ccl-loading > div'));
      
      expect(loading.nativeElement.getAttribute('role')).toBe('status');
      expect(loading.nativeElement.getAttribute('aria-label')).toBe('Loading...');
    });

    it('should have default aria-label when no label provided', () => {
      component.loadingLabel = '';
      fixture.detectChanges();
      
      const loading = fixture.debugElement.query(By.css('ccl-loading > div'));
      expect(loading.nativeElement.getAttribute('aria-label')).toBe('Loading…');
    });
  });

  describe('Focus Management', () => {
    it('should have focusable elements', () => {
      const button = fixture.debugElement.query(By.css('ccl-button button'));
      const input = fixture.debugElement.query(By.css('ccl-input input'));
      
      expect(button.nativeElement.tabIndex).not.toBe(-1);
      expect(input.nativeElement.tabIndex).not.toBe(-1);
    });

    it('should have proper tab order', () => {
      const button = fixture.debugElement.query(By.css('ccl-button button'));
      const input = fixture.debugElement.query(By.css('ccl-input input'));
      
      // Elements should be focusable in document order
      expect(button.nativeElement.compareDocumentPosition(input.nativeElement) & Node.DOCUMENT_POSITION_FOLLOWING).toBeTruthy();
    });
  });

  describe('Color and Contrast', () => {
    it('should have proper error styling', () => {
      component.inputError = true;
      fixture.detectChanges();
      
      const errorMessage = fixture.debugElement.query(By.css('ccl-input .ccl-input__error'));
      const styles = getComputedStyle(errorMessage.nativeElement);
      
      // Error text should have sufficient contrast
      expect(errorMessage.nativeElement.classList.contains('ccl-input__error')).toBe(true);
    });

    it('should have proper required field styling', () => {
      const requiredSpan = fixture.debugElement.query(By.css('ccl-input .ccl-input__required'));
      const styles = getComputedStyle(requiredSpan.nativeElement);
      
      // Required indicator should be visible
      expect(requiredSpan.nativeElement.textContent).toBe('*');
    });
  });

  describe('Screen Reader Support', () => {
    it('should have proper semantic structure', () => {
      const button = fixture.debugElement.query(By.css('ccl-button button'));
      const input = fixture.debugElement.query(By.css('ccl-input input'));
      const label = fixture.debugElement.query(By.css('ccl-input label'));
      
      // Button should be a button element
      expect(button.nativeElement.tagName).toBe('BUTTON');
      
      // Input should be an input element
      expect(input.nativeElement.tagName).toBe('INPUT');
      
      // Label should be a label element
      expect(label.nativeElement.tagName).toBe('LABEL');
    });

    it('should have proper heading hierarchy', () => {
      component.modalOpen = true;
      fixture.detectChanges();
      
      const modalTitle = fixture.debugElement.query(By.css('ccl-modal h2'));
      expect(modalTitle.nativeElement.tagName).toBe('H2');
    });

    it('should announce dynamic content appropriately', () => {
      const toast = fixture.debugElement.query(By.css('ccl-toast > div'));
      const loading = fixture.debugElement.query(By.css('ccl-loading > div'));
      
      // Toast should have live region
      expect(toast.nativeElement.getAttribute('aria-live')).toBeTruthy();
      
      // Loading should have status role
      expect(loading.nativeElement.getAttribute('role')).toBe('status');
    });
  });
});
