import {Component, EventEmitter, Input, Output} from '@angular/core';
import {FieldType, Operator, Predicate, Query} from "../query-builder/query-builder.component";
import {JsonPipe, KeyValuePipe, NgForOf, NgIf} from "@angular/common";
import {FormsModule, ReactiveFormsModule} from "@angular/forms";
import {v4 as uuidv4} from 'uuid';
import {SchemaField} from "../../../app/search/search.component";

@Component({
  selector: 'app-query',
  standalone: true,
  imports: [
    NgForOf,
    ReactiveFormsModule,
    FormsModule,
    NgIf,
    JsonPipe,
    KeyValuePipe
  ],
  templateUrl: './query.component.html',
  styleUrl: './query.component.css'
})
export class QueryComponent {

  @Input() query!: Query;
  @Input() fields!: SchemaField[];

  @Output() removeQuery = new EventEmitter<void>();
  @Output() queryChanged = new EventEmitter<void>();

  queryId = uuidv4();

  constructor() {}

  onFieldChange(predicate: Predicate, event: Event): void {
    const selectElement = event.target as HTMLSelectElement;
    const selectedValue = selectElement.value;
    const selectedField = this.fields.find(field => field.name === selectedValue);

    if(!selectedField) {
      return;
    }

    predicate.field = selectedField;
    predicate.operator = selectedField.validOperators[0];
  }

  hasFieldsInCategory(category: string): boolean {
    return this.fields.some(field => field.category === category);
  }

  onOperatorChange(predicate: Predicate, event: Event): void {
    const selectElement = event.target as HTMLSelectElement;
    const selectedOperatorType = selectElement.value;
    const selectedOperator = predicate.field?.validOperators.find(operator => operator.operatorType === selectedOperatorType);
    if (selectedOperator) {
      predicate.operator = selectedOperator;
      this.queryChanged.emit(); // Assuming `queryChanged` is an EventEmitter you've defined somewhere in your component
    }
  }

  addPredicate(): void {
    this.query.predicates.push({ field: null, operator: null, value: null });
    this.queryChanged.emit();
  }

  removePredicate(index: number): void {
    this.query.predicates.splice(index, 1);
    this.queryChanged.emit();
  }

  addSubQuery(): void {
    if (!this.query.childQueries) {
      this.query.childQueries = [];
    }
    this.query.childQueries.push({ predicates: [], logicalOperator: 'AND' });
    this.queryChanged.emit();
  }

  removeSubQuery(index: number): void {
    // @ts-ignore
    this.query.childQueries.splice(index, 1);
    this.queryChanged.emit();
  }

  osuMods: { [key: string]: number } = {
    "NF": 1,
    "EZ": 2,
    "HD": 8,
    "HR": 16,
    "SD": 32,
    "DT": 64,
    "RL": 128,
    "HT": 256,
    "NC": 512,
    "FL": 1024
  };

  onModChange(event: any, predicate: Predicate) {
    const modValue = parseInt(event.target.value);
    const currentMods = predicate.value as number || 0;

    if (event.target.checked) {
      predicate.value = currentMods | modValue;
    } else {
      predicate.value = currentMods & ~modValue;
    }

    this.queryChanged.emit();
  }

  getSelectedMods(predicate: Predicate): string[] {
    const currentMods = predicate.value as number || 0;
    return Object.entries(this.osuMods)
      .filter(([_, value]) => (currentMods & value) !== 0)
      .map(([key]) => key);
  }

  isModSelected(predicate: Predicate, modValue: number): boolean {
    const currentMods = predicate.value as number || 0;
    return (currentMods & modValue) !== 0;
  }

}
