import { HttpClient } from '@angular/common/http';
import { Injectable } from '@angular/core';
import { ParticipantStatus } from '@msfa-enums/participant-status.enum';
import { SortOrder } from '@msfa-enums/sort-order.enum';
import { environment } from '@msfa-environment';
import {
  mapParticipantApiResponseToParticipant,
  Participant,
  ParticipantApiResponse,
  ParticipantsApiResponse,
} from '@msfa-models/participant.model';
import { Sort } from '@msfa-models/sort.model';
import { sort } from '@msfa-utils/sort.util';
import { BehaviorSubject, combineLatest, Observable } from 'rxjs';
import { map } from 'rxjs/operators';

function filterParticipants(participants: Participant[], searchFilter: string): Participant[] {
  return participants.filter(participant => {
    const searchValueExistsInName = participant.fullName.toLowerCase().includes(searchFilter.toLowerCase());
    const searchValueExistsInErrandNumber = participant.errandNumber.toString().includes(searchFilter);

    return searchValueExistsInName || searchValueExistsInErrandNumber;
  });
}

@Injectable({
  providedIn: 'root',
})
export class ParticipantsService {
  private _apiBaseUrl = `${environment.api.url}/participants`;
  private _allParticipants$: Observable<Participant[]> = this.httpClient
    .get<ParticipantsApiResponse>(this._apiBaseUrl)
    .pipe(map(response => response.data.map(participant => mapParticipantApiResponseToParticipant(participant))));
  private _activeParticipantsSortBy$ = new BehaviorSubject<Sort<keyof Participant> | null>({
    key: 'handleBefore',
    order: SortOrder.ASC,
  });
  public activeParticipantsSortBy$: Observable<
    Sort<keyof Participant>
  > = this._activeParticipantsSortBy$.asObservable();
  private _followUpParticipantsSortBy$ = new BehaviorSubject<Sort<keyof Participant> | null>({
    key: 'handleBefore',
    order: SortOrder.ASC,
  });
  public followUpParticipantsSortBy$: Observable<
    Sort<keyof Participant>
  > = this._followUpParticipantsSortBy$.asObservable();
  private _searchFilter$ = new BehaviorSubject<string>('');
  public searchFilter$: Observable<string> = this._searchFilter$.asObservable();

  public filteredParticipants$: Observable<Participant[]> = combineLatest([
    this._allParticipants$,
    this._searchFilter$,
  ]).pipe(map(([participants, searchFilter]) => filterParticipants(participants, searchFilter)));

  public activeParticipants$: Observable<Participant[]> = combineLatest([
    this.filteredParticipants$,
    this._activeParticipantsSortBy$,
  ]).pipe(
    map(([participants, sortBy]) => {
      const activeParticipants = participants.filter(participant => participant.status === ParticipantStatus.ACTIVE);
      return sortBy ? sort(activeParticipants, sortBy) : activeParticipants;
    })
  );

  public followUpParticipants$: Observable<Participant[]> = combineLatest([
    this.filteredParticipants$,
    this._followUpParticipantsSortBy$,
  ]).pipe(
    map(([participants, sortBy]) => {
      const followUpParticipants = participants.filter(
        participant => participant.status === ParticipantStatus.FOLLOW_UP
      );
      return sortBy ? sort(followUpParticipants, sortBy) : followUpParticipants;
    })
  );

  public fetchDetailedParticipantData$(id: string): Observable<Participant> {
    return this.httpClient
      .get<ParticipantApiResponse>(`${this._apiBaseUrl}/${id}`)
      .pipe(map(result => mapParticipantApiResponseToParticipant(result.data)));
  }

  public setSearchFilter(value: string): void {
    this._searchFilter$.next(value);
  }

  public setActiveParticipantsSortKey(key: keyof Participant): void {
    const currentSortBy = this._activeParticipantsSortBy$.getValue();
    let order = currentSortBy.order;
    if (currentSortBy?.key === key) {
      order = order === SortOrder.ASC ? SortOrder.DESC : SortOrder.ASC;
    }
    this._activeParticipantsSortBy$.next({ key, order });
  }

  public setFollowUpParticipantsSortKey(key: keyof Participant): void {
    const currentSortBy = this._followUpParticipantsSortBy$.getValue();
    let order = currentSortBy.order;
    if (currentSortBy?.key === key) {
      order = order === SortOrder.ASC ? SortOrder.DESC : SortOrder.ASC;
    }
    this._followUpParticipantsSortBy$.next({ key, order });
  }

  constructor(private httpClient: HttpClient) {}
}
