import {
  AfterContentInit,
  ChangeDetectionStrategy,
  ChangeDetectorRef,
  Component,
  ContentChildren,
  forwardRef,
  Input,
  QueryList,
} from '@angular/core';
import { ControlValueAccessor, NG_VALUE_ACCESSOR } from '@angular/forms';
import { UiCheckboxComponent } from './checkbox.component';

@Component({
  selector: 'ui-checkbox-group',
  templateUrl: 'checkbox-group.component.html',
  styleUrls: ['checkbox-group.component.scss'],
  changeDetection: ChangeDetectionStrategy.OnPush,
  providers: [
    {
      provide: NG_VALUE_ACCESSOR,
      useExisting: forwardRef(() => UiCheckboxGroupComponent),
      multi: true,
    },
  ],
})
export class UiCheckboxGroupComponent implements AfterContentInit, ControlValueAccessor {
  @Input() max: number = undefined; // undefined = infinite active checkboxes possible

  values: any[] = [];
  disabled: boolean;

  @ContentChildren(UiCheckboxComponent, { read: UiCheckboxComponent, descendants: true })
  checkboxes: QueryList<UiCheckboxComponent>;

  private onChange = (v: any) => {};
  private onTouched = () => {};

  constructor(private cdr: ChangeDetectorRef) {}

  writeValue(obj: any): void {
    this.values = Array.isArray(obj) ? [...obj] : [];
    this.updateValuesOfChildren();
    this.cdr.markForCheck();
  }
  registerOnChange(fn: any): void {
    this.onChange = fn;
  }
  registerOnTouched(fn: any): void {
    this.onTouched = fn;
  }
  setDisabledState?(isDisabled: boolean): void {
    this.disabled = isDisabled;
    this.setDisabledStateOfChildren(isDisabled);
  }

  ngAfterContentInit(): void {
    this.registerOnCheckboxChange();
    this.updateValuesOfChildren();
    this.setDisabledStateOfChildren(this.disabled);
    this.checkboxes.changes.subscribe(() => {
      this.registerOnCheckboxChange();
      this.updateValuesOfChildren();
      this.setDisabledStateOfChildren(this.disabled);
    });
  }

  setDisabledStateOfChildren(isDisabled: boolean) {
    this.checkboxes?.forEach((checkbox) => {
      checkbox.setDisabledState(isDisabled);
    });
  }

  updateValuesOfChildren() {
    this.checkboxes?.forEach((checkbox) => {
      checkbox.selectValue(
        this.values?.find((value) => value === checkbox.value),
        false
      );
    });
  }

  registerOnCheckboxChange() {
    this.checkboxes.forEach((cb) => cb.registerOnChangeForParent((c, v) => this.checkboxChanged(c, v)));
  }

  checkboxChanged(checked: boolean, value: any) {
    if (checked) {
      this.values.push(value);
    } else {
      this.values = this.values.filter((v) => v !== value);
    }

    this.validateCheckboxes();
    this.updateValuesOfChildren();

    this.onChange(this.values);
    this.onTouched();
  }

  validateCheckboxes(): void {
    if (this.max === undefined) {
      return;
    }
    while (this.values.length > this.max) {
      this.values = this.values.filter((v, i) => i !== 0);
    }
  }
}
