import { Component, NgZone, inject, OnInit } from '@angular/core';
import { ActivatedRoute, Data, ParamMap, Router, RouterModule } from '@angular/router';
import { combineLatest, filter, Observable, Subscription, tap, map } from 'rxjs';
import { NgbModal } from '@ng-bootstrap/ng-bootstrap';
import { HttpResponse } from '@angular/common/http';
import { MatProgressSpinnerModule } from '@angular/material/progress-spinner';

import SharedModule from 'app/shared/shared.module';
import { sortStateSignal, SortDirective, SortByDirective, type SortState, SortService } from 'app/shared/sort';
import { DurationPipe, FormatMediumDatetimePipe, FormatMediumDatePipe } from 'app/shared/date';
import { FormsModule, ReactiveFormsModule } from '@angular/forms';
import { SORT, ITEM_DELETED_EVENT, DEFAULT_SORT_DATA } from 'app/config/navigation.constants';
import { IVariable } from '../variable.model';
import { EntityArrayResponseType, VariableService } from '../service/variable.service';
import { VariableDeleteDialogComponent } from '../delete/variable-delete-dialog.component';
import { VariableSearchFormService, VariableSearchFormGroup } from './variable-search-form.service';
import { IVariableScope } from 'app/entities/variable-scope/variable-scope.model';
import { VariableScopeService } from 'app/entities/variable-scope/service/variable-scope.service';
import { IVariableCategory } from 'app/entities/variable-category/variable-category.model';
import { VariableCategoryService } from 'app/entities/variable-category/service/variable-category.service';

@Component({
  standalone: true,
  selector: 'jhi-variable',
  templateUrl: './variable.component.html',
  styleUrl: './variable.component.css',
  imports: [
    RouterModule,
    FormsModule,
	ReactiveFormsModule,
    SharedModule,
    SortDirective,
    SortByDirective,
    DurationPipe,
    FormatMediumDatetimePipe,
    FormatMediumDatePipe,
    MatProgressSpinnerModule,
  ],
})
export class VariableComponent implements OnInit {
  subscription: Subscription | null = null;
  variables?: IVariable[];
  isLoading = false;
  isExporting: boolean = false;

  sortState = sortStateSignal({});

  variableScopesSharedCollection: IVariableScope[] = [];
  variableCategoriesSharedCollection: IVariableCategory[] = [];
  
  public router = inject(Router);
  protected variableService = inject(VariableService);
  protected variableSearchFormService = inject(VariableSearchFormService);
  protected activatedRoute = inject(ActivatedRoute);
  protected sortService = inject(SortService);
  protected modalService = inject(NgbModal);
  protected ngZone = inject(NgZone);
  protected variableScopeService = inject(VariableScopeService);
  protected variableCategoryService = inject(VariableCategoryService);

  // eslint-disable-next-line @typescript-eslint/member-ordering
  searchForm: VariableSearchFormGroup = this.variableSearchFormService.createVariableSearchFormGroup();
  trackId = (_index: number, item: IVariable): number => this.variableService.getEntityIdentifier(item);

  compareVariableScope = (o1: IVariableScope | null, o2: IVariableScope | null): boolean =>
    this.variableScopeService.compareEntity(o1, o2);

  compareVariableCategory = (o1: IVariableCategory | null, o2: IVariableCategory | null): boolean =>
    this.variableCategoryService.compareEntity(o1, o2);
	
  ngOnInit(): void {
    /*
    DON'T LOAD on startup. Let the user select some filters
    this.subscription = combineLatest([this.activatedRoute.queryParamMap, this.activatedRoute.data])
      .pipe(
        tap(([params, data]) => this.fillComponentAttributeFromRoute(params, data)),
        tap(() => this.load()),
      )
      .subscribe();
	  */
    
    // Listen to changes to the scope filter property
    this.searchForm.get('variableScopeId')?.valueChanges.subscribe((scopeId) => {
      this.loadCategoriesOfSelectedScope(scopeId);
      this.searchForm.get('variableCategoryId')?.setValue(null);
    });
    
    this.loadRelationshipsOptions();
  }

  delete(variable: IVariable): void {
    const modalRef = this.modalService.open(VariableDeleteDialogComponent, { size: 'lg', backdrop: 'static' });
    modalRef.componentInstance.variable = variable;
    // unsubscribe not needed because closed completes on modal close
    modalRef.closed
      .pipe(
        filter(reason => reason === ITEM_DELETED_EVENT),
        tap(() => this.load()),
      )
      .subscribe();
  }

  onSearch(): void {
	  this.load();
  }
  
  load(): void {
    this.queryBackend().subscribe({
      next: (res: EntityArrayResponseType) => {
        this.onResponseSuccess(res);
      },
    });
  }

  navigateToWithComponentValues(event: SortState): void {
    this.handleNavigation(event);
  }

  // Tri-state checkbox helpers
  isChecked(control: any): boolean {
	  if (control && control.value != null) {
	    return control.value;
	  }
	  return false;
  }

  isUnChecked(control: any): boolean {
	  if (control && control.value != null) {
	    return !control.value;
	  }
	  return false;
  }
  
  isUndetermined(control: any): boolean {
	if (!control || control.value == null) {
	  return true;
	}
	return false;
  }
  
  toggleState(control: any): void {
    if (control) {
      const value = control.value;
      if (value === null) {
        control.setValue(true);
      } else if (value === true) {
      control.setValue(false);
      } else if (value === false) {
      control.setValue(null);
      }
    }
  }
  
  export(): void {
    this.isExporting = true;

    this.variableService.export().subscribe((blob: Blob) => {
      const a = document.createElement('a');
      const objectUrl = URL.createObjectURL(blob);
      a.href = objectUrl;
      a.download = 'report.xlsx';
      a.click();
      URL.revokeObjectURL(objectUrl);

      this.isExporting = false;
    });
  }

  protected fillComponentAttributeFromRoute(params: ParamMap, data: Data): void {
    this.sortState.set(this.sortService.parseSortParam(params.get(SORT) ?? data[DEFAULT_SORT_DATA]));
  }

  protected onResponseSuccess(response: EntityArrayResponseType): void {
    const dataFromBody = this.fillComponentAttributesFromResponseBody(response.body);
    this.variables = this.refineData(dataFromBody);
  }

  protected refineData(data: IVariable[]): IVariable[] {
    const { predicate, order } = this.sortState();
    return predicate && order ? data.sort(this.sortService.startSort({ predicate, order })) : data;
  }

  protected fillComponentAttributesFromResponseBody(data: IVariable[] | null): IVariable[] {
    return data ?? [];
  }

  protected queryBackend(): Observable<EntityArrayResponseType> {
    this.isLoading = true;
    const queryObject: any = {
      eagerload: true,
      sort: this.sortService.buildSortParam(this.sortState()),
    };
	
    // Apply search values to the queryObject sent in the request, for server-side creation of a query criteria
    const variableSearch = this.variableSearchFormService.getVariable(this.searchForm);
    if (variableSearch) {
      Object.entries(variableSearch).forEach(([key, value]) => {
      var clause: string = "contains";	//Default
        if (value !== null && value !== undefined) {
        switch(typeof value) { 
          case 'string': {
          // Don't search with an empty string criteria
          if (value.trim() === "") return;
          clause = "contains";
          break;
        }
        case 'boolean': {
          clause = "equals";
          break;
        }
        case 'number': {
          clause = "equals";
          break;
        }
        }
        
        queryObject[key + "." + clause] = value;
      }
      });
    }
	
    return this.variableService.queryByCriteria(queryObject).pipe(tap(() => (this.isLoading = false)));
  }

  protected handleNavigation(sortState: SortState): void {
    const queryParamsObj = {
      sort: this.sortService.buildSortParam(sortState),
    };

    this.ngZone.run(() => {
      this.router.navigate(['./'], {
        relativeTo: this.activatedRoute,
        queryParams: queryParamsObj,
      });
    });
  }
  
  protected loadCategoriesOfSelectedScope(scopeId: number|null|undefined): void {
    if (scopeId) {
      this.variableCategoryService
          .queryByScope(scopeId)
          .pipe(map((res: HttpResponse<IVariableCategory[]>) => res.body ?? []))
          .subscribe((cats: IVariableCategory[]) => (this.variableCategoriesSharedCollection = cats));
    } else {
      this.variableCategoriesSharedCollection = [];
    }
  }
  
  protected loadRelationshipsOptions(): void {
    this.variableScopeService
      .query()
      .pipe(map((res: HttpResponse<IVariableScope[]>) => res.body ?? []))
      .subscribe((variableScopes: IVariableScope[]) => (this.variableScopesSharedCollection = variableScopes));

  }
}
