import { TypographyDynamicHeadingLevel } from '@af/digi-ng/_typography/typography-dynamic-heading';
import {
  Component,
  ChangeDetectionStrategy,
  Input,
  Output,
  EventEmitter,
  OnChanges,
  SimpleChanges,
} 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 OnChanges {
  @Input() treeNodeModel: TreeNodeModel;
  @Input() headingLevel: TypographyDynamicHeadingLevel = TypographyDynamicHeadingLevel.H3;
  @Input() headingText: string;
  @Input() showGeneralInfo: boolean;
  @Input() generalInfo: string;
  @Input() visibleChildren: Array<TreeNodeModel>;
  @Output() filterVisibleChildrenRequested = new EventEmitter<FilterTreeNodeData>();
  @Output() selectedNodesChanged = new EventEmitter<TreeNodeModel>();

  readonly ButtonType = ButtonType;
  readonly FormInputSearchVariation = FormInputSearchVariation;

  childNodeVisibleChildren: Array<TreeNodeModel>;

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

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

    super.unsubscribeOnDestroy(
      this.filterTreeNodeDebouncer.pipe(debounceTime(200)).subscribe(text => {
        this.filterVisibleChildrenRequested.emit({ text, treeNode: this.treeNodeModel });
      })
    );
  }

  ngOnChanges(changes: SimpleChanges): void {
    let expandedChildNode: TreeNodeModel | null = null;

    if (changes.visibleChildren) {
      expandedChildNode = this.visibleChildren?.find(childNode => this.isExpandedNode(this.treeNodeModel, childNode));

      this.updateChildNodeVisibleChildren({
        text: expandedChildNode?.filterText,
        treeNode: expandedChildNode,
      });
    }
  }

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

    this.filterTreeNodeDebouncer.next(event.detail.target.value);
  }

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

  onToggleSelected(treeNode: TreeNodeModel, event: CustomEvent<{ target: { checked: boolean } }>): void {
    if (!treeNode || !event?.detail?.target) {
      return;
    }

    treeNode.isSelected = event?.detail?.target?.checked;

    this.selectedNodesChanged.emit(this.treeNodeModel);
  }

  onToggleAllChildLeafNodes(treeNode: TreeNodeModel): void {
    let allChildLeafNodesAreSelected = false;

    if (!treeNode || !treeNode.children) {
      return;
    }

    allChildLeafNodesAreSelected = this.allChildLeafNodesAreSelected(treeNode);

    treeNode.children = treeNode.children.map(child => {
      return { ...child, isSelected: !allChildLeafNodesAreSelected };
    });

    this.selectedNodesChanged.emit(this.treeNodeModel);
  }

  onSetExpandedChild(parentTreeNode: TreeNodeModel, treeNode: TreeNodeModel): void {
    if (!parentTreeNode || !treeNode) {
      return;
    }

    parentTreeNode.expandedChildUuid = parentTreeNode.expandedChildUuid === treeNode.uuid ? null : treeNode.uuid;

    this.updateChildNodeVisibleChildren({ text: treeNode.filterText, treeNode });
  }

  updateExpandedChildPanel(treeNode: TreeNodeModel): void {
    if (!this.childNodeVisibleChildren) {
      return;
    }

    this.childNodeVisibleChildren = this.treeNodesSelectorService.getVisibleChildren(treeNode);
  }

  updateChildNodeVisibleChildren(filterTreeNodeData: FilterTreeNodeData): void {
    if (!filterTreeNodeData || !filterTreeNodeData.treeNode) {
      return;
    }

    filterTreeNodeData.treeNode.children = this.treeNodesSelectorService.getFilteredTreeNodeChildren(
      filterTreeNodeData
    );

    filterTreeNodeData.treeNode.filterText = filterTreeNodeData.text;

    this.childNodeVisibleChildren = this.treeNodesSelectorService.getVisibleChildren(filterTreeNodeData.treeNode);
  }

  getFilterButtonAriaLabelText(treeNode: TreeNodeModel): string {
    return this.treeNodesSelectorService.getFilterButtonAriaLabelText(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);
  }

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

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