import { TypographyDynamicHeadingLevel } from '@af/digi-ng/_typography/typography-dynamic-heading';
import {
  Component,
  OnInit,
  ChangeDetectionStrategy,
  Input,
  OnChanges,
  SimpleChanges,
  Output,
  EventEmitter,
} from '@angular/core';
import { UnsubscribeDirective } from '@msfa-directives/unsubscribe.directive';
import { ButtonType } from '../../../../../pages/avrop/enums/button-type.enum';
import { FormInputSearchVariation } from '../../../../../pages/avrop/enums/form-input-search-variation';
import { Subject } from 'rxjs';
import { debounceTime } from 'rxjs/operators';
import {
  FilterTreeNodeData,
  TreeNodeModel,
  TreeNodesSelectorService,
} from '../../services/tree-nodes-selector.service';

@Component({
  selector: 'msfa-expanded-tree-node',
  templateUrl: './expanded-tree-node.component.html',
  styleUrls: ['./expanded-tree-node.component.scss'],
  changeDetection: ChangeDetectionStrategy.OnPush,
})
export class ExpandedTreeNodeComponent extends UnsubscribeDirective implements OnInit, OnChanges {
  @Input() treeNodeModel: TreeNodeModel | null = null;
  @Input() headingLevel: TypographyDynamicHeadingLevel = TypographyDynamicHeadingLevel.H3;
  @Input() latestParentActionKey: string;
  @Output() filterTreeNodeRequested = new EventEmitter<FilterTreeNodeData>();
  @Output() clickAndFocusElementRequested = new EventEmitter<string>();

  readonly ButtonType = ButtonType;
  readonly FormInputSearchVariation = FormInputSearchVariation;

  visibleChildren: Array<TreeNodeModel> | null = null;

  private readonly filterTreeNodeDebouncer: Subject<FilterTreeNodeData> = new Subject<FilterTreeNodeData>();

  constructor(private treeNodesSelectorService: TreeNodesSelectorService) {
    super();

    super.unsubscribeOnDestroy(
      this.filterTreeNodeDebouncer.pipe(debounceTime(200)).subscribe(filterTreeNodeData => {
        this.filterTreeNodeRequested.emit(filterTreeNodeData);
      })
    );
  }

  ngOnInit(): void {
    this.refreshComponentData();
  }

  ngOnChanges(changes: SimpleChanges): void {
    if (changes.latestParentActionKey || changes.treeNodeModel) {
      this.refreshComponentData();
    }
  }

  private refreshComponentData(): void {
    this.visibleChildren = this.treeNodesSelectorService.getVisibleChildren(this.treeNodeModel);
  }

  onFilterTextChanged(event: CustomEvent<{ target: { value: string } }>, treeNode: TreeNodeModel): void {
    if (!treeNode || !event?.detail?.target) {
      return;
    }

    this.filterTreeNodeDebouncer.next({
      text: event.detail.target.value,
      treeNode,
    });
  }

  onFocusOutsideFilter(event: Event): void {
    event.preventDefault();
    event.stopPropagation();
  }

  nodePresentationToggleAllClicked(treeNode: TreeNodeModel): void {
    if (!treeNode) {
      return;
    }

    this.clickAndFocusElementRequested.emit(`#${this.treeNodesSelectorService.getToggleAllButtonId(treeNode)}`);
  }

  nodePresentationItemClicked(treeNode: TreeNodeModel): void {
    if (!treeNode) {
      return;
    }

    this.clickAndFocusElementRequested.emit(`#${this.treeNodesSelectorService.getItemButtonId(treeNode)}`);
  }

  getPresentationItemId(treeNode: TreeNodeModel): string {
    return this.treeNodesSelectorService.getPresentationItemId(treeNode);
  }

  getPresentationToggleAllId(treeNode: TreeNodeModel): string {
    return this.treeNodesSelectorService.getPresentationToggleAllId(treeNode);
  }

  getFilterDescriptionId(treeNode: TreeNodeModel): string {
    return this.treeNodesSelectorService.getFilterDescriptionId(treeNode);
  }

  getFilterButtonAriaLabelText(treeNode: TreeNodeModel): string {
    return this.treeNodesSelectorService.getFilterButtonAriaLabelText(treeNode);
  }

  getTreeNodeHeadingText(treeNode: TreeNodeModel): string {
    return this.treeNodesSelectorService.getTreeNodeHeadingText(treeNode);
  }

  hasChildLeafNodes(node: TreeNodeModel): boolean {
    return this.treeNodesSelectorService.hasChildLeafNodes(node);
  }

  allChildLeafNodesAreSelected(node: TreeNodeModel): boolean {
    return this.treeNodesSelectorService.allChildLeafNodesAreSelected(node);
  }

  isLeafNode(node: TreeNodeModel): boolean {
    return this.treeNodesSelectorService.isLeafNode(node);
  }

  isExpandedNode(parentTreeNode: TreeNodeModel, treeNode: TreeNodeModel): boolean {
    return this.treeNodesSelectorService.isExpandedNode(parentTreeNode, treeNode);
  }

  hasSelectedDescendant(treeNode: TreeNodeModel): boolean {
    return this.treeNodesSelectorService.hasSelectedLeafNodeDescendant(treeNode);
  }
}
