import { ComponentFixture, TestBed } from '@angular/core/testing';
import { DataTableComponent, DataTableColumn } from './datatable';
import { By } from '@angular/platform-browser';

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

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

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

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

  describe('Input Properties', () => {
    it('should have default values', () => {
      expect(component.columns).toEqual([]);
      expect(component.rows).toEqual([]);
      expect(component.striped).toBe(false);
      expect(component.bordered).toBe(false);
      expect(component.compact).toBe(false);
    });

    it('should accept columns input', () => {
      const columns: DataTableColumn[] = [
        { id: 'name', label: 'Name' },
        { id: 'age', label: 'Age' }
      ];
      component.columns = columns;
      fixture.detectChanges();
      expect(component.columns).toEqual(columns);
    });

    it('should accept rows input', () => {
      const rows = [
        { name: 'Alice', age: 25 },
        { name: 'Bob', age: 30 }
      ];
      component.rows = rows;
      fixture.detectChanges();
      expect(component.rows).toEqual(rows);
    });

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

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

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

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

    it('should apply base CSS class', () => {
      const table = fixture.debugElement.query(By.css('table'));
      expect(table.nativeElement.classList).toContain('ccl-datatable');
    });

    it('should render table wrapper', () => {
      const wrapper = fixture.debugElement.query(By.css('.ccl-datatable-wrapper'));
      expect(wrapper).toBeTruthy();
    });

    it('should render table header', () => {
      component.columns = [{ id: 'name', label: 'Name' }];
      fixture.detectChanges();
      const thead = fixture.debugElement.query(By.css('thead'));
      expect(thead).toBeTruthy();
    });

    it('should render table body', () => {
      component.columns = [{ id: 'name', label: 'Name' }];
      component.rows = [{ name: 'Alice' }];
      fixture.detectChanges();
      const tbody = fixture.debugElement.query(By.css('tbody'));
      expect(tbody).toBeTruthy();
    });
  });

  describe('Column Rendering', () => {
    it('should render headers from columns', () => {
      component.columns = [{ id: 'name', label: 'Name' }];
      fixture.detectChanges();
      const th = fixture.debugElement.query(By.css('th'));
      expect(th.nativeElement.textContent).toContain('Name');
    });

    it('should render multiple headers', () => {
      component.columns = [
        { id: 'name', label: 'Name' },
        { id: 'age', label: 'Age' }
      ];
      fixture.detectChanges();
      const headers = fixture.debugElement.queryAll(By.css('th'));
      expect(headers.length).toBe(2);
      expect(headers[0].nativeElement.textContent).toContain('Name');
      expect(headers[1].nativeElement.textContent).toContain('Age');
    });

    it('should set column width when provided', () => {
      component.columns = [{ id: 'name', label: 'Name', width: '200px' }];
      fixture.detectChanges();
      const th = fixture.debugElement.query(By.css('th'));
      expect(th.nativeElement.style.width).toBe('200px');
    });

    it('should set auto width when width not provided', () => {
      component.columns = [{ id: 'name', label: 'Name' }];
      fixture.detectChanges();
      const th = fixture.debugElement.query(By.css('th'));
      expect(th.nativeElement.style.width).toBe('auto');
    });

    it('should set proper ARIA attributes for headers', () => {
      component.columns = [{ id: 'name', label: 'Name' }];
      fixture.detectChanges();
      const th = fixture.debugElement.query(By.css('th'));
      expect(th.nativeElement.getAttribute('role')).toBe('columnheader');
      expect(th.nativeElement.getAttribute('scope')).toBe('col');
    });
  });

  describe('Row Rendering', () => {
    it('should render rows from data', () => {
      component.columns = [{ id: 'name', label: 'Name' }];
      component.rows = [{ name: 'Alice' }];
      fixture.detectChanges();
      const td = fixture.debugElement.query(By.css('td'));
      expect(td.nativeElement.textContent).toContain('Alice');
    });

    it('should render multiple rows', () => {
      component.columns = [{ id: 'name', label: 'Name' }];
      component.rows = [
        { name: 'Alice' },
        { name: 'Bob' }
      ];
      fixture.detectChanges();
      const rows = fixture.debugElement.queryAll(By.css('tbody tr'));
      expect(rows.length).toBe(2);
    });

    it('should render multiple columns per row', () => {
      component.columns = [
        { id: 'name', label: 'Name' },
        { id: 'age', label: 'Age' }
      ];
      component.rows = [{ name: 'Alice', age: 25 }];
      fixture.detectChanges();
      const cells = fixture.debugElement.queryAll(By.css('td'));
      expect(cells.length).toBe(2);
      expect(cells[0].nativeElement.textContent).toContain('Alice');
      expect(cells[1].nativeElement.textContent).toContain('25');
    });

    it('should handle missing data gracefully', () => {
      component.columns = [{ id: 'name', label: 'Name' }];
      component.rows = [{ name: 'Alice' }, {}];
      fixture.detectChanges();
      const cells = fixture.debugElement.queryAll(By.css('td'));
      expect(cells[0].nativeElement.textContent).toContain('Alice');
      expect(cells[1].nativeElement.textContent.trim()).toBe('');
    });

    it('should set proper ARIA attributes for rows and cells', () => {
      component.columns = [{ id: 'name', label: 'Name' }];
      component.rows = [{ name: 'Alice' }];
      fixture.detectChanges();
      const row = fixture.debugElement.query(By.css('tbody tr'));
      const cell = fixture.debugElement.query(By.css('td'));
      expect(row.nativeElement.getAttribute('role')).toBe('row');
      expect(cell.nativeElement.getAttribute('role')).toBe('cell');
    });
  });

  describe('Empty State', () => {
    it('should show empty message when no rows', () => {
      component.columns = [{ id: 'name', label: 'Name' }];
      component.rows = [];
      fixture.detectChanges();
      const empty = fixture.debugElement.query(By.css('.ccl-datatable__empty'));
      expect(empty.nativeElement.textContent).toContain('No data available');
    });

    it('should show empty message when rows is null', () => {
      component.columns = [{ id: 'name', label: 'Name' }];
      component.rows = null as any;
      fixture.detectChanges();
      const empty = fixture.debugElement.query(By.css('.ccl-datatable__empty'));
      expect(empty.nativeElement.textContent).toContain('No data available');
    });

    it('should set colspan to match number of columns', () => {
      component.columns = [
        { id: 'name', label: 'Name' },
        { id: 'age', label: 'Age' }
      ];
      component.rows = [];
      fixture.detectChanges();
      const empty = fixture.debugElement.query(By.css('.ccl-datatable__empty'));
      expect(empty.nativeElement.getAttribute('colspan')).toBe('2');
    });

    it('should not show empty message when rows exist', () => {
      component.columns = [{ id: 'name', label: 'Name' }];
      component.rows = [{ name: 'Alice' }];
      fixture.detectChanges();
      const empty = fixture.debugElement.query(By.css('.ccl-datatable__empty'));
      expect(empty).toBeNull();
    });
  });

  describe('Variant Classes', () => {
    it('should apply striped class when striped=true', () => {
      component.striped = true;
      fixture.detectChanges();
      const table = fixture.debugElement.query(By.css('table'));
      expect(table.nativeElement.classList).toContain('ccl-datatable--striped');
    });

    it('should not apply striped class when striped=false', () => {
      component.striped = false;
      fixture.detectChanges();
      const table = fixture.debugElement.query(By.css('table'));
      expect(table.nativeElement.classList).not.toContain('ccl-datatable--striped');
    });

    it('should apply bordered class when bordered=true', () => {
      component.bordered = true;
      fixture.detectChanges();
      const table = fixture.debugElement.query(By.css('table'));
      expect(table.nativeElement.classList).toContain('ccl-datatable--bordered');
    });

    it('should not apply bordered class when bordered=false', () => {
      component.bordered = false;
      fixture.detectChanges();
      const table = fixture.debugElement.query(By.css('table'));
      expect(table.nativeElement.classList).not.toContain('ccl-datatable--bordered');
    });

    it('should apply compact class when compact=true', () => {
      component.compact = true;
      fixture.detectChanges();
      const table = fixture.debugElement.query(By.css('table'));
      expect(table.nativeElement.classList).toContain('ccl-datatable--compact');
    });

    it('should not apply compact class when compact=false', () => {
      component.compact = false;
      fixture.detectChanges();
      const table = fixture.debugElement.query(By.css('table'));
      expect(table.nativeElement.classList).not.toContain('ccl-datatable--compact');
    });

    it('should apply multiple variant classes', () => {
      component.striped = true;
      component.bordered = true;
      component.compact = true;
      fixture.detectChanges();
      const table = fixture.debugElement.query(By.css('table'));
      expect(table.nativeElement.classList).toContain('ccl-datatable--striped');
      expect(table.nativeElement.classList).toContain('ccl-datatable--bordered');
      expect(table.nativeElement.classList).toContain('ccl-datatable--compact');
    });
  });

  describe('Accessibility', () => {
    it('should have proper table role', () => {
      const table = fixture.debugElement.query(By.css('table'));
      expect(table.nativeElement.getAttribute('role')).toBe('table');
    });

    it('should have proper row roles', () => {
      component.columns = [{ id: 'name', label: 'Name' }];
      component.rows = [{ name: 'Alice' }];
      fixture.detectChanges();
      const rows = fixture.debugElement.queryAll(By.css('tr'));
      rows.forEach(row => {
        expect(row.nativeElement.getAttribute('role')).toBe('row');
      });
    });
  });
});
