import {Component, EventEmitter, Output} from '@angular/core';
import {Need} from '../../models/Need';
import {CupboardService} from '../../services/cupboard.service';
import {UsersService} from '../../services/users.service';
import {userType} from '../../models/User';
import {AuthService} from '../../services/auth.service';
import {catchError, of} from 'rxjs';
import {ToastsService, ToastType} from '../../services/toasts.service';

interface sortAlgo {
  (a: Need,b: Need): number;
}

// sort functions
const sortByName: sortAlgo = (a: Need, b: Need): number => {
  if(a.name.toLocaleLowerCase() < b.name.toLocaleLowerCase()) {
    return -1;
  }
  return 1;
}

const sortByGoal: sortAlgo = (a: Need, b: Need): number => {
  if(a.maxGoal == b.maxGoal) {
    return sortByName(a,b);
  }
  else if(a.maxGoal > b.maxGoal) {
    return -1;
  }
  return 1;
}

const sortByCompletion: sortAlgo = (a: Need, b: Need): number => {
  if(a.current == b.current) {
    return sortByGoal(a,b);
  }
  else if(a.current > b.current) {
    return -1;
  }
  return 1;
}

const sortByPriority: sortAlgo = (a: Need, b: Need): number => {
  if(a.urgent == b.urgent) {
    return sortByGoal(a,b);
  }
  else if(a.urgent && !b.urgent) {
    return -1;
  }
  return 1;
}

const sortByLocation: sortAlgo = (a: Need, b: Need): number => {
  if(a.location.toLocaleLowerCase() < b.location.toLocaleLowerCase()) {
    return -1;
  }
  return 1;
}

@Component({
  selector: 'app-need-list',
  standalone: false,
  templateUrl: './need-list.component.html',
  styleUrl: './need-list.component.css'
})
export class NeedListComponent {
  selectedNeed: Need | null = null;
  needs: Need[] = [];
  searchResults: Need[] = [];
  visibleNeeds: Need[] = [];
  sortMode: 'Ascending' | 'Descending' = 'Ascending'
  currentPage: number = 0;
  itemsPerPage: number = 5;
  totalPages: number = Math.ceil(this.needs.length / this.itemsPerPage);

  decrementPage() {
    this.currentPage--;
    this.updateVisibleNeeds();
  }

  incrementPage() {
    this.currentPage++;
    this.updateVisibleNeeds();
  }

  lastPage() {
      this.currentPage = this.totalPages - 1
      this.updateVisibleNeeds()
  }

  firstPage() {
      this.currentPage = 0
      this.updateVisibleNeeds()
  }

  editNeedsPerPage(amount: number) {
    this.itemsPerPage = amount;
    this.updateVisibleNeeds();
  }

  updateVisibleNeeds() {
    this.totalPages = Math.ceil(this.searchResults.length / this.itemsPerPage);
    this.visibleNeeds = this.searchResults.slice(this.currentPage * this.itemsPerPage, (this.currentPage + 1) * this.itemsPerPage);
  }

  resetVisibleNeeds() {
    this.currentPage = 0;
    this.updateVisibleNeeds();
  }

  currentSortAlgo: sortAlgo = sortByPriority;
  sortSelection: string = 'sortByPriority';

  SortingAlgoArrays: {func:sortAlgo,name:string, display:string[]}[] = [
    {func:sortByPriority,name:"sortByPriority", display:["Highest Priority", "Lowest Priority"]},
    {func:sortByName,name:"sortByName", display:["Name (A to Z)", "Name (Z to A)"]},
    {func:sortByLocation,name:"sortByLocation", display:["Location (A to Z)", "Location (Z to A)"]},
    {func:sortByCompletion,name:"sortByCompletion", display:["Most Completed", "Least Completed"]},
    {func:sortByGoal,name:"sortByGoal", display:["Largest Maximum Goal", "Smallest Maximum Goal"]},
  ];

  @Output() currentNeed = new EventEmitter<Need>();

  constructor(
    private cupboardService: CupboardService,
    private usersService: UsersService,
    private authService: AuthService,
    private toastService: ToastsService
  ) {}

    refresh() {
        this.cupboardService.getNeeds().subscribe(n => {
          if (this.sortMode == 'Ascending') {
            this.needs = n.sort(this.currentSortAlgo);
          } else {
            this.needs = n.sort(this.currentSortAlgo).reverse();
          }
          this.searchResults = this.needs;
          this.updateVisibleNeeds();
        });

        const form = document.getElementById('search-form') as HTMLFormElement;
        form.reset();
        this.search(null);
    }

  ngOnInit(): void {
    this.refresh()

  }

  changeSortMode(form : any) {
    if (this.sortMode == 'Ascending'){
      this.sortMode = 'Descending'
    } else {
      this.sortMode = 'Ascending'
    }
    this.search(form)
  }

  private searchDelay: any;

  async search(form: any) {
    //wait .25 seconds before searching but cancel if another search is made during the wait to prevent too many api calls

    //remove previous search if it exists
    if (this.searchDelay) {
      clearTimeout(this.searchDelay);
    }
    if (form) {
      this.searchDelay = setTimeout(() => {

        if (form) {
          //sorting based on algo selected
          this.SortingAlgoArrays.forEach(algo => {
            if(algo.name === this.sortSelection) {
              this.currentSortAlgo = algo.func;
              console.log("changed sorting algorithm to: ", algo.name + this.sortMode)
              return
            }
          });

          const currentSearchValue = form.search; //latest value of the search
          this.cupboardService.searchNeeds(currentSearchValue).subscribe((n) => {
            if (this.sortMode == 'Ascending') {
              this.searchResults = n.sort(this.currentSortAlgo);
            } else {
              this.searchResults = n.sort(this.currentSortAlgo).reverse();
            }
            this.updateVisibleNeeds();
            });
          }
        }, 250);
      } else {
        //user has cleared the search bar, we can skip the timeout for a 1/4 second faster response
        //clear timeout to stop pending search
        clearTimeout(this.searchDelay);
        this.searchResults = this.needs;
      }
  }

  delete(id : number) {
    this.cupboardService.deleteNeed(id).subscribe(() => {
        this.toastService.sendToast(ToastType.INFO, "Need deleted.")
      this.needs = this.needs.filter(n => n.id !== id)
    })
    this.refresh();
  }

  isManager() {
    const type = this.authService.getCurrentUser()?.type;
    return type === ("MANAGER" as unknown as userType);
  }

  isHelper() {
    const type = this.authService.getCurrentUser()?.type;
    return type === ("HELPER" as unknown as userType);
  }

  changeText(id : number, text : string) {
    const span = document.getElementById('hover-status-label-' + id);
    if (span) {
      span.innerHTML = ' ' + text;
    }
  }

  add(need: Need) {
    const currentUser = this.authService.getCurrentUser();
    //console.log("get current user in angular:", currentUser)
    if (currentUser) {
      if (!currentUser.basket.includes(need.id)) {
        currentUser.basket.push(need.id);
        this.usersService.updateUser(currentUser)
            .pipe(catchError((err, _) =>  {
                console.error(err);
                return of();
            }))
            .subscribe(() => {
                this.usersService.refreshBasket();
            });
      } else {
        this.toastService.sendToast(ToastType.ERROR, "This need is already in your basket!")
      }
    }
  }

  back() {
    this.searchResults = this.needs;
  }

  select(need : Need) {
    //emit value
    this.currentNeed.emit(need);
    if (this.selectedNeed) {
      //revert already selected need to previous style
      console.log(need.id);
      let button = document.getElementById('need-button-' + this.selectedNeed.id);
      if (button) {
        console.log(button)
        button.style.background = 'lightgray';
        button.style.marginLeft = '0%';
        button.style.width = '98%';
      }
      button = document.getElementById('need-edit-button-' + this.selectedNeed.id);
      if (button) {
        button.style.visibility = 'visible';
      }
    }
      //change selected need to selected style
      this.selectedNeed = need;
      let button = document.getElementById('need-button-' + need.id);
      if (button) {
        button.style.background = 'white';
        button.style.marginLeft = '4%';
        button.style.width = '100%';
      }
      button = document.getElementById('need-edit-button-' + need.id);
      if (button) {
        button.style.visibility = 'hidden';
      }
  }
}