import { AfterViewInit, ChangeDetectorRef, Component, DoCheck, ElementRef, EventEmitter, Input, OnChanges, OnDestroy, OnInit, Output, Renderer2, ViewChild } from '@angular/core';
import { MatMenuTrigger } from '@angular/material/menu';
import { MatDialog } from '@angular/material/dialog';
import { ResourceGroupNode, ResourceNode } from '../sidebar-data';
import { AppDragDropService, AppDragMoveEvent } from 'src/app/shared/drag/app-drag-drop.service';


export interface NodeChangeEvent{
  prevContainer: string;
  currContainer: string;
  prevIndex: number;
  currIndex: number;
}

export interface DragResourceEvent{
  appDrag: AppDragMoveEvent,
  resource: ResourceNode
}

export interface MenuRecord{
  title: string,
  icon: string,
  handler: Function,
  primary?: boolean
}

@Component({
  selector: 'app-resource-group',
  templateUrl: './resource-group.component.html',
  styleUrls: ['./resource-group.component.scss']
})
export class ResourceGroupComponent implements OnInit, OnDestroy, OnChanges, AfterViewInit, DoCheck {

  @Input() data: ResourceGroupNode;

  /**
   * In ungroup case you can not get the reference the resources of the group, where the resources array contains the ungrouped resources
   * So only in that case, you can override this behaviour, and set a reference to the data.getUngroupedData
   */
  @Input() additionalResources?: ResourceNode[] = [];
  @Input() allClose?: boolean = false; // all group should be closed, when drag happened on group level
  @Input('menu') menuSource?: MenuRecord[] = []; 
  @ViewChild(MatMenuTrigger) trigger: MatMenuTrigger;
  
  @ViewChild("group", {read: ElementRef}) group: any;

  @Output('resourceDragEnded') resourceDragEndedEvent: EventEmitter<DragResourceEvent> = new EventEmitter();
  @Output('groupOpenStateChange') onGroupOpenStateChange: EventEmitter<boolean> = new EventEmitter<boolean>();
 
  public onDragAutoOpenMove; // handler, trigger when an element is dragged
  public isDraggedCursorOverThis = false;
  public currHeight = 0;
  private lastClosedState: boolean;
  private lastChildNumber: number;



  constructor(
    public dialog: MatDialog, 
    private renderer: Renderer2, 
    private el: ElementRef,
    private appDragDropService: AppDragDropService,
    //private cdRef:ChangeDetectorRef
  ) {}

  ngAfterViewInit(){
    this.lastClosedState = this.data.closed;
    this.lastChildNumber = this.data.resources.length+this.additionalResources.length;
    this.changeStyle();
    //this.cdRef.detectChanges();
  }

  ngDoCheck(){
    if (this.data.closed !== this.lastClosedState || this.data.resources.length+this.additionalResources.length != this.lastChildNumber){
      
      this.lastClosedState = this.data.closed;
      this.lastChildNumber = this.data.resources.length+this.additionalResources.length;

      if (this.group){
        setTimeout(()=>{
          this.changeStyle();
        }, 1);
      }
    }
  }

  ngOnInit(): void {
    // auto open the group, when the mouse moved over this component
    this.onDragAutoOpenMove = (pos, comp)=>{

      // close the submenu, you can drag the component and open the submenu in the same time on mobile, when you use longpress on the title
      this.trigger.closeMenu(); 

      this.changeStyle();
      if (!this.data.closed) return; // we already opened 

      if (this.checkCursorIsOverThis(pos)){
        
        this.isDraggedCursorOverThis = true;

        // if we are still waiting over the element after x sec, lets open this
        setTimeout(()=>{
          if (this.isDraggedCursorOverThis){
            this.data.closed = false;
            this.onGroupOpenStateChange.emit(this.data.closed); // bubble up to the server services
          }
        }, 500);
      }
      else{
        this.isDraggedCursorOverThis = false;
      }
    }

    this.appDragDropService.subscribeDragMove(this.onDragAutoOpenMove);
    

  }

  private checkCursorIsOverThis(pos){
    let bond = this.el.nativeElement.getBoundingClientRect();
    return (pos.x >= bond.left && pos.y > bond.top && pos.x <= bond.left + bond.width && pos.y <= bond.top + bond.height);
  }

  ngOnDestroy(){
    this.appDragDropService.unsubscribeDragMove(this.onDragAutoOpenMove);
  }

  ngOnChanges(e){
    if (this.group){
      this.changeStyle();
    }
  }

  toggle(){
    // we wont wait for the subscribe effect, because we have to call the changeStyle
    this.data.closed = !this.data.closed;
    if (this.group){ 
      this.changeStyle();
    }
    this.onGroupOpenStateChange.emit(this.data.closed); // bubble up to the server services
  }

  private changeStyle(){
    
    if (!this.data.closed && !this.allClose){
      this.currHeight = 48 + Math.max(24, this.group.nativeElement.querySelector('.group-body').getBoundingClientRect().height);
    }
    else{
      this.currHeight = 24;
    }
    
    this.group.nativeElement.style.height = this.currHeight+'px';
  }

  public resourceDragEnded(ev: AppDragMoveEvent, res: ResourceNode){
    this.resourceDragEndedEvent.emit({
      appDrag: ev,
      resource: res
    });
  }

  openMenu(event: any){
    event.stopPropagation();
    this.trigger.openMenu();
  }

}
