import {
  Component,
  ContentChildren,
  ElementRef,
  EventEmitter,
  Injector,
  Input,
  Output,
  QueryList,
  TemplateRef,
  ViewChild,
  ViewChildren
} from '@angular/core';
import { LoggerService } from '@isp/xdce-arch-core-base';
import { NbpBaseComponent, NbpStyle, WidgetMode } from '@isp/xdce-widget/base';
import { NbpFidToggleTabComponent } from './nbp-fid-toggle-tab.component';

let nextId = 0;

@Component({
  templateUrl: './nbp-fid-toggle-tabset.component.a11y.html',
  styleUrls: ['./nbp-fid-tab-toggle.component.a11y.scss']
})
export class NbpFidToggleTabsetComponentA11Y extends NbpBaseComponent {
  protected isA11Y = true;
  wngContent: TemplateRef<any>;

  /**
   * (Opzionale) Enum per impostare lo stile del pulsante.
   * "DEFAULT" | "PRIMARY" | "SECONDRY"
   *  Valore default: "DEFAULT"
   */
  @Input() nbpStyle: NbpStyle = NbpStyle.DEFAULT;

  /**
   * (Opzionale) String che definisce un identificativo univoco del tab bar
   * Utilizzato per gli attributi wai-aria
   */
  @Input() tabBarId = `${++nextId}`;  

  /**
* (Opzionale) input contenente il nome accessibile della tab bar
*/
  @Input('aria-label') public ariaLabel: string;
  /**
   * (Opzionale) input contenente l'id dell'elemento DOM da associare come nome accessibile alla tab bar.
   *  Se valorizzato, {@link ariaLabel} sara' ignorato dallo screen-reader.
   */
  @Input('aria-labelledby') public ariaLabelledBy: string;

  _selectedTabIndex = 0;
  /**
 * Indice della scheda selezionata
 */
  @Input()
  set nbpSelectedIndex(value: number) {
    if (this._selectedTabIndex !== value) {
      this._selectedTabIndex = value;
      this.nbpSelectedIndexChange.emit(this._selectedTabIndex);
    }
  }
  get nbpSelectedIndex(): number {
    return this._selectedTabIndex;
  }
  _style: any = NbpStyle;
  // @Input() vertical ;
  @Output() onSelect = new EventEmitter();
  @Output() nbpSelectedIndexChange = new EventEmitter<number>();

  @ContentChildren(NbpFidToggleTabComponent) tabs: QueryList<NbpFidToggleTabComponent>;

  @ViewChild('tabsContainer') tabsContainer: ElementRef;
  @ViewChild('tabPanels', { read: ElementRef }) tabPanels: ElementRef;
  @ViewChildren('spanWithTooltip') spanRefs: QueryList<ElementRef>;


  ngAfterContentInit() {
    const actives = this.tabs.filter(t => t.active);
    if (actives.length > 1) {
      this.loggerService.error(`Multiple active tabs set 'active'`);
    } else if (!actives.length && this.tabs.length) {
      this.tabs.first.active = true;
    }
  }

  ngAfterViewInit() {
    if (this.tabPanels && this.tabPanels.nativeElement) {
      const tabs: HTMLCollection = this.tabPanels.nativeElement.children;
      const tabsArray = Array.from(tabs);
      tabsArray.forEach((tab, index) => {
        tab.id = `toggletab-tabpanel-${this.tabBarId}-${index}`;
      });
    }
  }

  focusSpan(index: string, disabled: boolean): void {
    const spanId: string = 'toggletab-span-' + index;
    const spanRef = this.spanRefs.find(ref => ref.nativeElement.id === spanId);
    if (spanRef && !disabled) {
      spanRef.nativeElement.dispatchEvent(new Event('focusin'));
    } 
  }

  focusoutSpan(index: string, disabled: boolean): void {
    const spanId: string = 'toggletab-span-' + index;
    const spanRef = this.spanRefs.find(ref => ref.nativeElement.id === spanId);
    if (spanRef && !disabled) {
      spanRef.nativeElement.dispatchEvent(new Event('focusout'));
    } 
  }

  tabClicked(event: any, tab: NbpFidToggleTabComponent, index: number) {
    event.preventDefault();

    if (tab.disabled) {
      return;
    }
    this.tabs.forEach(element => element.active = false);
    tab.active = true;
    this.selectTab(index, tab.disabled);
    this.onSelect.emit(tab);
  }

  selectTab(index: number, disabledTab: boolean) {
    if (this._selectedTabIndex !== index && !disabledTab) {
      this.nbpSelectedIndex = index;
    }
  }

  constructor(private loggerService: LoggerService, injector: Injector) {
    super(injector);
  }
  isCorporate() {
    return WidgetMode.CORPORATE === this.widgetMode;
  }


  /**
   * Metodo per la navigazione da tastiera e l'attivazione del focus tra le varie tabs.
   * Lettura al keydown degli eventi ArrowLeft e ArrowRight per spostarsi a sinistra e a destra tra le tab;
   * Home e End per passare alla prima e ultima tab.
   */
  handleTablistKeydown(event: KeyboardEvent, currentTabIndex: number) {
    let nextTabIndex: number = undefined;
    const nbpItemsLength: number = this.tabs.length;

    switch (event.key) {
      case 'ArrowLeft':
        event.preventDefault();
        nextTabIndex = this.getLeftTabIndex(event, currentTabIndex, nbpItemsLength);
        break;
      case 'ArrowRight':
        event.preventDefault();
        nextTabIndex = this.getRightTabIndex(event, currentTabIndex, nbpItemsLength);
        break;
      case 'Home':
        event.preventDefault();
        nextTabIndex = this.getFirstTabIndex(event, 0, nbpItemsLength);
        break;
      case 'End':
        event.preventDefault();
        nextTabIndex = this.getLastTabIndex(event, nbpItemsLength - 1, nbpItemsLength);
        break;
      default:
        break;
    }

    if (nextTabIndex !== undefined) {
      let nextTabElement = document.getElementById(`toggletab-${this.tabBarId}-${nextTabIndex}`);
      if (nextTabElement) {
        nextTabElement.focus();
        this.scrollIntoViewIfNeeded(nextTabElement);
      }
    }
  }

  /**
  * Metodo per passare al tab a sinistra,
  * Se currentTabIndex è il primo tab della tablist il nextTabIndex ricavato sarà l'ultimo a destra
  * Il metodo invoca checkTabDisabled per controllare se nextTabIndex sia disabled,
  * ricavando il primo tab a sinistra selezionabile
  */
  private getLeftTabIndex(event: KeyboardEvent, currentTabIndex: number, nbpItemsLength: number): number {
    let nextTabIndex: number = (currentTabIndex - 1 + nbpItemsLength) % nbpItemsLength;
    let nextTabElement = document.getElementById(`toggletab-${this.tabBarId}-${nextTabIndex}`);
    nextTabIndex = this.checkTabDisabled(event, nextTabElement, nextTabIndex, nbpItemsLength);
    return nextTabIndex;
  }

  /**
  * Metodo per passare al tab a destra,
  * Se currentTabIndex è l'ultimo tab della tablist il nextTabIndex ricavato sarà l'ultimo a sinistra
  * Il metodo invoca checkTabDisabled per controllare se nextTabIndex sia disabled,
  * ricavando il primo tab a destra selezionabile
  */
   private getRightTabIndex(event: KeyboardEvent, currentTabIndex: number, nbpItemsLength: number): number {
    let nextTabIndex: number = (currentTabIndex + 1) % nbpItemsLength;
    let nextTabElement = document.getElementById(`toggletab-${this.tabBarId}-${nextTabIndex}`);
    nextTabIndex = this.checkTabDisabled(event, nextTabElement, nextTabIndex, nbpItemsLength);
    return nextTabIndex;
  }

  /**
  * Metodo per passare al primo tab a sinistra,
  * Il metodo invoca checkTabDisabled per controllare se nextTabIndex sia disabled,
  * ricavando il tab più a sinistra selezionabile
  */
  private getFirstTabIndex(event: KeyboardEvent, currentTabIndex: number, nbpItemsLength: number): number {
    let nextTabIndex: number = currentTabIndex;
    let nextTabElement = document.getElementById(`toggletab-${this.tabBarId}-${nextTabIndex}`);
    nextTabIndex = this.checkTabDisabled(event, nextTabElement, nextTabIndex, nbpItemsLength);
    return nextTabIndex;
  }

   /**
  * Metodo per passare all'ultimo tab a sinistra,
  * Il metodo invoca checkTabDisabled per controllare se nextTabIndex sia disabled,
  * ricavando il tab più a destra selezionabile
  */
  private getLastTabIndex(event: KeyboardEvent, currentTabIndex: number, nbpItemsLength: number): number {
    let nextTabIndex: number = currentTabIndex;
    let nextTabElement = document.getElementById(`toggletab-${this.tabBarId}-${nextTabIndex}`);
    nextTabIndex = this.checkTabDisabled(event, nextTabElement, nextTabIndex, nbpItemsLength);
    return nextTabIndex;
  }

  /**
  * Metodo per controllare lo stato disabled del tab,
  * Nel caso in cui lo stato sia disabled, il controllo del tab verrà passato al successivo
  */
  private checkTabDisabled(event: KeyboardEvent, nextTabElement: HTMLElement, nextTabIndex: number, nbpItemsLength: number): number {
    const isDisabled = nextTabElement.className.includes('disabled');
    if (isDisabled) {
      if (event.key === 'Home') {
        nextTabIndex = this.getFirstTabIndex(event, nextTabIndex + 1, nbpItemsLength);
      } else if (event.key === 'End') {
        nextTabIndex = this.getLastTabIndex(event, nextTabIndex - 1, nbpItemsLength);
      } else if (event.key === 'ArrowLeft') {
        nextTabIndex = this.getLeftTabIndex(event, nextTabIndex, nbpItemsLength);
      } else if (event.key === 'ArrowRight') {
        nextTabIndex = this.getRightTabIndex(event, nextTabIndex, nbpItemsLength);
      }
    }
    return nextTabIndex;
  }

  private scrollIntoViewIfNeeded(nextTabElement: HTMLElement) {
    let container = this.tabsContainer.nativeElement;
    let overLeft = nextTabElement.offsetLeft - container.offsetLeft < container.scrollLeft,
      overRight = (nextTabElement.offsetLeft - container.offsetLeft + nextTabElement.clientWidth)
        > (container.scrollLeft + container.clientWidth);

    if (overLeft || overRight) {
      container.scrollLeft = nextTabElement.offsetLeft - container.offsetLeft - container.clientWidth / 2 + nextTabElement.clientWidth / 2;
    }
  }
}
