import {Injectable} from '@angular/core';
import {environment} from '../../environments/environment';
import {HttpClient, HttpParams} from '@angular/common/http';
import {Observable, of} from 'rxjs';
import {Category} from '@shared/models/category.model';
import {Pentest} from '@shared/models/pentest.model';
import {Store} from '@ngxs/store';
import {ProjectState} from '@shared/stores/project-state/project-state';
import {catchError, map, switchMap} from 'rxjs/operators';
import {getTempPentestsForCategory} from '@shared/functions/categories/get-temp-pentests-for-category.function';
import {Finding} from '@shared/models/finding.model';

@Injectable({
  providedIn: 'root'
})
export class PentestService {

  private apiBaseURL = `${environment.apiEndpoint}/pentests`;

  constructor(
    private http: HttpClient,
    private readonly store: Store) {
  }

  /**
   * Load Pentests
   * @param category the categories of which the pentests should be requested
   */
  public loadPentests(category: Category): Observable<Pentest[]> {
    return this.store.select(ProjectState.project).pipe(
      switchMap(project => this.getPentestByProjectIdAndCategory(project.id, category)),
      catchError(_ => of(null)),
      map((response: Pentest[]) => {
        // ToDo: Improve performance by only loading templates when not all pentests of category got returned
        // Load template pentest
        const templatePentests = getTempPentestsForCategory(category);
        // The pentests that get returned to the component
        let completePentests: Pentest[] = response;
        // Add pentest template to complete pentests if not included in request
        if (completePentests) {
          templatePentests.forEach((templatePentest: Pentest) => {
            if (!completePentests.map(it => it.refNumber).includes(templatePentest.refNumber)) {
              completePentests.push(templatePentest);
            }
          });
        } else {
          completePentests = templatePentests;
        }
        return completePentests;
      })
    );
  }

  /**
   * Get Pentests
   * @param projectId the id of the project
   * @param category the categories of which the pentests should be requested
   */
  private getPentestByProjectIdAndCategory(projectId: string, category: Category): Observable<Pentest[]> {
    const queryParams = new HttpParams().append('projectId', projectId).append('category', Category[category]);
    return this.http.get<Pentest[]>(`${this.apiBaseURL}`, {params: queryParams});
  }

  /**
   * Save Pentest
   * @param pentest the information of the Pentest
   */
  public savePentest(projectId: string, pentest: Pentest): Observable<Pentest> {
    return this.http.post<Pentest>(`${this.apiBaseURL}/${projectId}`, pentest);
  }

  /**
   * Update Pentest
   * @param pentest the information of the Pentest
   */
  public updatePentest(pentest: Pentest): Observable<Pentest> {
    return this.http.patch<Pentest>(`${this.apiBaseURL}/${pentest.id}`, pentest);
  }
}
