import { Directive, ElementRef, booleanAttribute, computed, contentChildren, inject, input, model } from '@angular/core';

type <%= classify(name) %>Id = string;

let nextId = 0;

@Directive({
  selector: '[<%= camelize(name) %>]',
  exportAs: '<%= camelize(name) %>',
})
export class <%= classify(name) %> {
  private readonly instanceId = `<%= dasherize(name) %>-${nextId++}`;
  private readonly tabs = contentChildren(<%= classify(name) %>Tab, { descendants: true });

  readonly activeId = model<<%= classify(name) %>Id | null>(null);

  private readonly resolvedActiveId = computed<<%= classify(name) %>Id | null>(() => {
    const activeId = this.activeId();
    const tabs = this.tabs();
    if (activeId !== null && tabs.some((tab) => tab.value() === activeId && !tab.disabled())) {
      return activeId;
    }

    return (
      tabs.find((tab) => tab.selected() && !tab.disabled()) ??
      tabs.find((tab) => !tab.disabled()) ??
      tabs[0]
    )?.value() ?? null;
  });

  isActive(value: <%= classify(name) %>Id): boolean {
    return this.resolvedActiveId() === value;
  }

  select(tab: <%= classify(name) %>Tab): void {
    if (tab.disabled()) {
      return;
    }

    this.activeId.set(tab.value());
  }

  tabDomId(value: <%= classify(name) %>Id): string {
    return `${this.instanceId}-tab-${value}`;
  }

  panelDomId(value: <%= classify(name) %>Id): string {
    return `${this.instanceId}-panel-${value}`;
  }
}

@Directive({
  selector: '[<%= camelize(name) %>List]',
  exportAs: '<%= camelize(name) %>List',
  host: {
    role: 'tablist',
    '[attr.aria-label]': 'label() || null',
    '(keydown)': 'handleKeydown($event)',
  },
})
export class <%= classify(name) %>List {
  private readonly root = inject(<%= classify(name) %>);
  private readonly tabs = contentChildren(<%= classify(name) %>Tab, { descendants: true });

  readonly label = input('');

  // Left/Right/Home/End move focus AND selection (automatic activation model, per APG tabs pattern).
  handleKeydown(event: KeyboardEvent): void {
    const enabledTabs = this.tabs().filter((tab) => !tab.disabled());
    const currentIndex = enabledTabs.findIndex((tab) => tab.active());

    if (event.key === 'ArrowRight') {
      event.preventDefault();
      this.focusAt(enabledTabs, currentIndex + 1);
      return;
    }

    if (event.key === 'ArrowLeft') {
      event.preventDefault();
      this.focusAt(enabledTabs, currentIndex - 1);
      return;
    }

    if (event.key === 'Home') {
      event.preventDefault();
      this.focusAt(enabledTabs, 0);
      return;
    }

    if (event.key === 'End') {
      event.preventDefault();
      this.focusAt(enabledTabs, enabledTabs.length - 1);
    }
  }

  private focusAt(tabs: readonly <%= classify(name) %>Tab[], index: number): void {
    if (!tabs.length) {
      return;
    }

    const nextIndex = (index + tabs.length) % tabs.length;
    const tab = tabs[nextIndex];
    this.root.select(tab);
    tab.focus();
  }
}

@Directive({
  selector: '[<%= camelize(name) %>Tab]',
  exportAs: '<%= camelize(name) %>Tab',
  host: {
    role: 'tab',
    '[id]': 'root.tabDomId(value())',
    '[attr.aria-selected]': 'active()',
    '[attr.aria-controls]': 'root.panelDomId(value())',
    '[attr.aria-disabled]': 'disabled() ? "true" : null',
    '[attr.tabindex]': 'active() ? 0 : -1',
    '(click)': 'select()',
  },
})
export class <%= classify(name) %>Tab {
  protected readonly root = inject(<%= classify(name) %>);
  private readonly elementRef = inject<ElementRef<HTMLElement>>(ElementRef);

  readonly value = input.required<<%= classify(name) %>Id>();
  readonly selected = input(false, { transform: booleanAttribute });
  readonly disabled = input(false, { transform: booleanAttribute });
  readonly active = computed(() => this.root.isActive(this.value()));

  select(): void {
    this.root.select(this);
  }

  focus(): void {
    this.elementRef.nativeElement.focus();
  }
}

@Directive({
  selector: '[<%= camelize(name) %>Panel]',
  exportAs: '<%= camelize(name) %>Panel',
  host: {
    role: 'tabpanel',
    '[id]': 'root.panelDomId(value())',
    '[attr.aria-labelledby]': 'root.tabDomId(value())',
    '[attr.tabindex]': '0',
    '[hidden]': '!active()',
  },
})
export class <%= classify(name) %>Panel {
  protected readonly root = inject(<%= classify(name) %>);

  readonly value = input.required<<%= classify(name) %>Id>();
  readonly active = computed(() => this.root.isActive(this.value()));
}
