import { Component, OnInit, HostListener, ElementRef, forwardRef, ContentChildren, QueryList, AfterContentInit, Input, ViewChild } from '@angular/core';
import { NG_VALUE_ACCESSOR, ControlValueAccessor } from '@angular/forms';
import { NeuOptionComponent } from '../neu-option/neu-option.component';

export const CUSTOM_INPUT_CONTROL_VALUE_ACCESSOR:any = {
  provide: NG_VALUE_ACCESSOR,
  useExisting: forwardRef(() => NeuSelectComponent),
  multi: true
}

@Component({
  selector: 'neu-select',
  templateUrl: './neu-select.component.html',
  styleUrls: ['./neu-select.component.css'],
  providers: [CUSTOM_INPUT_CONTROL_VALUE_ACCESSOR]
})
export class NeuSelectComponent implements ControlValueAccessor, AfterContentInit {

  //atributs de valors
  active:boolean = false;

  private innerValue:any = '';
  private _options:QueryList<NeuOptionComponent>;
  @ContentChildren(NeuOptionComponent) set options(options:QueryList<NeuOptionComponent>) {
    if(options!=null && options!=undefined) {
      this._options = options;
      this._options.forEach(option => {
        option.selected.subscribe(evt => {
          this.content.nativeElement.innerHTML = evt.html
          this.value = evt.value;
        });
      });
    }
  }
  @Input("placeholder") placeholder:string;
  @ViewChild("content", {static: true}) content:ElementRef;
  @ViewChild("optionsDiv") optionsDiv:ElementRef;
  @ViewChild("neu_dropdown_title") neu_dropdown_title:ElementRef;

  //placeholders per els callbacks provided per control value accessor
  private onTouchedCallback:() => void;
  private onChangeCallback: (_:any) => void;

  constructor(private eRef: ElementRef) { }

  ngAfterContentInit() {
    this.content.nativeElement.innerHTML = this.placeholder;
  }

  //per quan cliquin fora del dropwdown, es plegui automaticament
  @HostListener('document:click', ['$event'])
  @HostListener('document:touchstart', ['$event'])
  clickout(event) {
    if(!this.eRef.nativeElement.contains(event.target)) {
      this.active = false;
    }
  }

  @HostListener('window:scroll', ['$event']) 
  onScroll($event) {
    if(this.active) {
      this.renderOptionsPosition();
    }
  } 

  get value():any {
    return this.innerValue;
  }

  set value(v:any) {
    if(v!==this.innerValue) {
      this.innerValue = v;
      this.onChangeCallback(v);
    }
  }
  
  //on blur event
  onBlur() {
    this.onTouchedCallback();
  }
  
  writeValue(value:any) {
    if(value && value!==this.innerValue) {
      this.innerValue = value;
      this._options?.forEach(o => { //si ja ve el valor donat de fora, doncs el posem
        if(JSON.stringify(o.value) === JSON.stringify(value)) {
          this.content.nativeElement.innerHTML = o.html;
        }
      });
    }
  }

  registerOnChange(fn:any) {
    this.onChangeCallback = fn;
  }

  registerOnTouched(fn:any) {
    this.onTouchedCallback = fn;
  }

  toggle() {
    if(this.active) {
      this.active = false;
    }
    else {
      this.renderOptionsPosition();
      this.active = true;
    }
  }

  private renderOptionsPosition() {
    //si te fixed en algun pare o ell mateix, no tenim en compte scroll, altrament si
    //console.log("getOffset fixed: ", this.getOffset().fixed, "getScroll fixed: ", this.getScroll().fixed, "getOffset absolute: ", this.getOffset().absolute, "getScroll absolute: ", this.getScroll().absolute, "heights: ", this.getOffset().y, this.getScroll().y, this.neu_dropdown_title.nativeElement.offsetHeight)
    this.optionsDiv.nativeElement.style.top = (this.getOffset().y - this.getScroll().y + this.neu_dropdown_title.nativeElement.offsetHeight) + "px";
    this.optionsDiv.nativeElement.style.left = (this.getOffset().x - this.getScroll().x) + "px";
    this.optionsDiv.nativeElement.style.width = `${this.neu_dropdown_title.nativeElement.offsetWidth }px`;
  }

  private getScroll(el = this.eRef.nativeElement) {
    if(el && el.parentNode) {
      var x = 0;
      var y = 0;

      var fixed = false;
      var absolute = false;

      while(el) {
        if(el && el.parentNode) {
          const position = window.getComputedStyle(el).position;
          fixed = position == "fixed" ;
          absolute = position == "absolute";
          if(fixed) {
            el = null;
            break;
          }
          else if(absolute) {
            el = null;
            //x = 0;
            //y = 0;
            break;
          }
          else {
            x += el.scrollLeft;
            y += el.scrollTop;
            el = el.parentNode;
          }
        } else {
          el = null;
        }
      }

      return {x: x, y: y, fixed: fixed, absolute: absolute};
    }

    return null;
  }

  private getOffset(el = this.eRef.nativeElement) {
    if(el && el.parentNode) {
      var x = 0;
      var y = 0;
      var fixed = false;
      var absolute = false;

      while(el) {
        const position = window.getComputedStyle(el).position;
        absolute = absolute ? absolute : position == "absolute";
        fixed = fixed ? fixed : position == "fixed";
        if(absolute) {
          el = null;
        }
        else {
          x += el.offsetLeft;
          y += el.offsetTop;
          el = el.offsetParent;
        }
      }

      return {x: x, y: y, fixed: fixed, absolute: absolute};
    }

    return null;
  }

}
