import {
  Component,
  OnInit,
  Input,
  ChangeDetectorRef,
  ViewChild,
  Output,
  EventEmitter,
  AfterViewInit,
  OnDestroy
} from '@angular/core';
import { MatTreeFlattener, MatTree } from '@angular/material';
import { NGXLogger } from 'ngx-logger';

import { DeptInfo } from '@ucap-webmessenger/protocol-query';
import { LoginResponse } from '@ucap-webmessenger/protocol-authentication';
import { FlatTreeControl } from '@angular/cdk/tree';
import { CdkVirtualScrollViewport } from '@angular/cdk/scrolling';
import { VirtualScrollTreeFlatDataSource } from '@ucap-webmessenger/ui';

interface OrganizationNode {
  deptInfo: DeptInfo;
  name: string;
  children?: OrganizationNode[];
}

/** Flat node with expandable and level information */
interface FlatNode {
  expandable: boolean;
  name: string;
  level: number;
  deptInfo: DeptInfo;
}

@Component({
  selector: 'ucap-organization-tree',
  templateUrl: './tree.component.html',
  styleUrls: ['./tree.component.scss']
})
export class TreeComponent implements OnInit, OnDestroy, AfterViewInit {
  @Output()
  selected = new EventEmitter<DeptInfo>();

  @Input()
  loginRes: LoginResponse;

  @Input()
  set oraganizationList(deptInfoList: DeptInfo[]) {
    if (!deptInfoList || 0 === deptInfoList.length) {
      return;
    }
    const nodeMap = new Map<number, OrganizationNode>();
    const rootNodeList: OrganizationNode[] = [];
    const remainChildNodeList: OrganizationNode[] = [];
    let myNode: OrganizationNode;

    deptInfoList.forEach(deptInfo => {
      const node: OrganizationNode = {
        deptInfo,
        name: deptInfo.name,
        children: []
      };
      if (nodeMap.has(deptInfo.seq)) {
        this.logger.warn('duplicate seq', deptInfo.seq);
        return;
      }
      nodeMap.set(deptInfo.seq, node);

      if (deptInfo.seq === this.loginRes.departmentCode) {
        myNode = node;
      }

      if (0 === deptInfo.parentSeq) {
        rootNodeList.push(node);
        return;
      }

      if (nodeMap.has(deptInfo.parentSeq)) {
        nodeMap.get(deptInfo.parentSeq).children.push(node);
      } else {
        remainChildNodeList.push(node);
      }
    });

    remainChildNodeList.forEach(node => {
      if (nodeMap.has(node.deptInfo.parentSeq)) {
        nodeMap.get(node.deptInfo.parentSeq).children.push(node);
      }
    });
    this.dataSource.data = rootNodeList;
  }

  @ViewChild('cvsvOrganization', { static: false })
  cvsvOrganization: CdkVirtualScrollViewport;

  @ViewChild('orgranizationTree', { static: false })
  orgranizationTree: MatTree<OrganizationNode>;

  treeControl: FlatTreeControl<FlatNode>;
  treeFlattener: MatTreeFlattener<OrganizationNode, FlatNode>;
  dataSource: VirtualScrollTreeFlatDataSource<OrganizationNode, FlatNode>;

  constructor(
    private changeDetectorRef: ChangeDetectorRef,
    private logger: NGXLogger
  ) {
    this.treeControl = new FlatTreeControl<FlatNode>(
      node => node.level,
      node => node.expandable
    );
    this.treeFlattener = new MatTreeFlattener<OrganizationNode, FlatNode>(
      (node: OrganizationNode, level: number) => {
        return {
          expandable: !!node.children && node.children.length > 0,
          name: node.name,
          level,
          deptInfo: node.deptInfo
        };
      },
      node => node.level,
      node => node.expandable,
      node => node.children
    );
    this.dataSource = new VirtualScrollTreeFlatDataSource<
      OrganizationNode,
      FlatNode
    >(this.treeControl, this.treeFlattener);
  }

  ngOnInit() {}

  ngOnDestroy(): void {
    this.logger.debug('-----------------------TreeComponent ngOnDestroy');
  }

  ngAfterViewInit(): void {
    this.dataSource.cdkVirtualScrollViewport = this.cvsvOrganization;
  }

  hasChild = (_: number, node: FlatNode) => node.expandable;

  onClickNode(node: OrganizationNode) {
    this.selected.emit(node.deptInfo);
  }
}
