import { Input, Output, EventEmitter, ChangeDetectorRef, Directive, OnInit, inject } from '@angular/core';
import { IdName } from '../_shared/utils/util';
import { Subject } from 'rxjs';
import { map } from 'rxjs/operators';
import { UntypedFormBuilder, UntypedFormGroup, Validators, AbstractControl } from '@angular/forms';

export interface FilterValue {
  id: number;
  name: string;
  filterId: number;
  dataSourceId: number;
  preview: string;
  value1: string;
  value2: string;
}

@Directive()
export class ControlBaseComponent implements OnInit {
  @Input() dataSourceId: number;
  @Input() filterId: number;
  @Input() parameterName: string;
  @Input() isRequired = false;
  @Input() controlStyle: string = null;
  @Output() valueUpdated = new EventEmitter();

  form: UntypedFormGroup
  mainCtrl: AbstractControl;
  myRef = inject(ChangeDetectorRef);
  myFb = inject(UntypedFormBuilder);

  constructor() {
  }

  ngOnInit(): void {
    this.form = this.myFb.group({
      mainControl: [null, this.isRequired ? Validators.required : Validators.nullValidator]
    });

    this.mainCtrl = this.form.controls['mainControl'];
  }

  valueUpdated$ = new Subject()
  hasValue = false;

  getValue(): string {
    //this should not be used, it should be overridden
    return null;
  }

  getFilterValue(): FilterValue {
    //this should not be used, it should be overridden
    return null;
  }

  setFilterValue(value: FilterValue) {
    console.log('this should not be used, it should be overridden: ' + value);
  }

  resetValue() {
    this.form.reset();
    this.valueUpdated$.next(null);
    this.myRef.detectChanges();
  }

  get isValid(): boolean {
    this.form.markAllAsTouched();
    this.myRef.detectChanges();
    if (this.mainCtrl)
      return this.mainCtrl.valid;
    else
      return true;
  }

  hasValueResult$ = this.valueUpdated$.pipe(
    map(() => {
      this.hasValue = this.getValue() !== null;
      this.valueUpdated.emit();
      return this.hasValue;
    })
  )

  getIdPreview(id: number, items: IdName[]): string {
    let preview: string = null;

    // If items haven't loaded yet, return null instead of 'Not Found'
    if (!items || items.length === 0)
      return null;

    if (id) {
      const name: string = items.find(item => item.id === id)?.name ?? 'Not Found';
      preview = name;
    }
    return preview;
  }

  getIdListPreview(selectedIds: number[], items: IdName[]): string {
    let preview: string = null;
    let names: string[] = [];

    // If items haven't loaded yet, return null instead of generating invalid preview
    if (!items || items.length === 0)
      return null;

    if (selectedIds?.length > 0) {
      names = selectedIds.map(id => {
        const name = items.find(item => item.id === id)?.name ?? 'Not Found';
        return name;
      })
      preview = this.getStringArrayPreview(names);
    }
    return preview;
  }

  getStringArrayPreview(items: string[]): string {
    let preview: string = null;
    if (items?.length > 0)
      preview = items.join('\u2022'); //don't use commas since they might be part of names
    return preview;
  }
}
