import { OverlayContainer } from '@angular/cdk/overlay';
import { Component, signal } from '@angular/core';
import { ComponentFixture, TestBed } from '@angular/core/testing';

import { FilterCard } from './filter-card';

@Component({
  standalone: true,
  imports: [FilterCard],
  template: `
    <app-filter-card
      title="Country Selection"
      [defaultCollapsed]="defaultCollapsed()"
      [collapsible]="collapsible()"
      [collapsedIcon]="collapsedIcon"
      [expandedIcon]="expandedIcon"
      [contentId]="contentId()"
      (collapseChanged)="changes.push($event)"
    >
      <button filterCardActions type="button">Reset</button>
      <input data-testid="projected-input" value="preserved" />
    </app-filter-card>
  `
})
class HostComponent {
  readonly defaultCollapsed = signal(false);
  readonly collapsible = signal(true);
  readonly contentId = signal('');
  readonly changes: boolean[] = [];
  collapsedIcon = 'custom-collapsed';
  expandedIcon = 'custom-expanded';
}

describe('FilterCard', () => {
  let fixture: ComponentFixture<HostComponent>;
  let host: HostComponent;
  let overlayContainer: OverlayContainer;

  const card = (): FilterCard => fixture.debugElement.children[0].componentInstance;
  const toggle = (): HTMLButtonElement => fixture.nativeElement.querySelector('button[aria-controls]');
  const icon = (): HTMLElement => toggle().querySelector('i') as HTMLElement;
  const bodyGrid = (): HTMLElement => fixture.nativeElement.querySelector('.filter-card-body-grid');

  beforeEach(async () => {
    await TestBed.configureTestingModule({ imports: [HostComponent] }).compileComponents();
    fixture = TestBed.createComponent(HostComponent);
    host = fixture.componentInstance;
    overlayContainer = TestBed.inject(OverlayContainer);
    fixture.detectChanges();
  });

  afterEach(() => {
    vi.useRealTimers();
    overlayContainer.ngOnDestroy();
  });

  it('starts expanded by default', () => {
    expect(card().collapsed()).toBe(false);
    expect(bodyGrid().classList.contains('is-collapsed')).toBe(false);
  });

  it('reacts to a collapsed default state', () => {
    host.defaultCollapsed.set(true);
    fixture.detectChanges();
    expect(card().collapsed()).toBe(true);
    expect(bodyGrid().classList.contains('is-collapsed')).toBe(true);
  });

  it('switches icons and tooltips when toggled', () => {
    expect(icon().className).toBe('custom-expanded');
    expect(toggle().getAttribute('aria-label')).toBe('Hide Filters');
    toggle().click();
    fixture.detectChanges();
    expect(icon().className).toBe('custom-collapsed');
    expect(toggle().getAttribute('aria-label')).toBe('Show Filters');
  });

  it('updates an open tooltip when toggled without requiring another hover', () => {
    vi.useFakeTimers();
    toggle().dispatchEvent(new MouseEvent('mouseenter'));
    vi.advanceTimersByTime(200);
    fixture.detectChanges();
    expect(overlayContainer.getContainerElement().textContent).toContain('Hide Filters');

    toggle().click();
    fixture.detectChanges();

    expect(overlayContainer.getContainerElement().textContent).toContain('Show Filters');
    expect(overlayContainer.getContainerElement().textContent).not.toContain('Hide Filters');
  });

  it('emits the new collapsed state', () => {
    toggle().click();
    toggle().click();
    expect(host.changes).toEqual([true, false]);
  });

  it('sets accessible expanded and controls attributes', () => {
    const id = card().resolvedContentId();
    expect(toggle().getAttribute('aria-expanded')).toBe('true');
    expect(toggle().getAttribute('aria-controls')).toBe(id);
    expect(fixture.nativeElement.querySelector(`#${id}`)).not.toBeNull();
  });

  it('keeps projected content mounted while collapsed', () => {
    const input = fixture.nativeElement.querySelector('[data-testid="projected-input"]');
    toggle().click();
    fixture.detectChanges();
    expect(fixture.nativeElement.querySelector('[data-testid="projected-input"]')).toBe(input);
    expect(fixture.nativeElement.textContent).toContain('Reset');
  });

  it('uses custom icons', () => {
    expect(icon().classList.contains('custom-expanded')).toBe(true);
    toggle().click();
    fixture.detectChanges();
    expect(icon().classList.contains('custom-collapsed')).toBe(true);
  });

  it('uses a custom content id', () => {
    host.contentId.set('state-filter-content');
    fixture.detectChanges();
    expect(toggle().getAttribute('aria-controls')).toBe('state-filter-content');
    expect(fixture.nativeElement.querySelector('#state-filter-content')).not.toBeNull();
  });

  it('generates a stable content id', () => {
    const generatedId = card().resolvedContentId();
    fixture.detectChanges();
    expect(generatedId).toMatch(/^filter-card-content-\d+$/);
    expect(card().resolvedContentId()).toBe(generatedId);
  });

  it('does not collapse or emit when non-collapsible', () => {
    host.collapsible.set(false);
    fixture.detectChanges();
    toggle().click();
    expect(card().collapsed()).toBe(false);
    expect(host.changes).toEqual([]);
    expect(toggle().disabled).toBe(true);
  });
});
