import {Component, OnInit} from '@angular/core';
import {SimilarReplay} from "../replays";
import {Observable} from "rxjs";
import {environment} from "../../environments/environment";
import {LocalCacheService} from "../../corelib/service/local-cache.service";
import {ActivatedRoute, Router, RouterLink} from "@angular/router";
import {FilterManagerService} from "../filter-manager.service";
import {FormsModule} from "@angular/forms";
import {DecimalPipe, NgForOf, NgIf, NgOptimizedImage} from "@angular/common";

export interface FilterStolenReplays {
  sorting?: string;

  minPP?: number;
  maxPP?: number;

  searchUsername?: string;
  searchBeatmap?: string;

  minSimilarity?: number;
  maxSimilarity?: number;
}

@Component({
  selector: 'app-view-similar-replays',
  standalone: true,
  templateUrl: './view-similar-replays.component.html',
  imports: [
    FormsModule,
    DecimalPipe,
    NgOptimizedImage,
    NgForOf,
    RouterLink,
    NgIf
  ],
  styleUrls: ['./view-similar-replays.component.css']
})
export class ViewSimilarReplaysComponent implements OnInit {

  isUrlFilters = false;

  originalScores: SimilarReplay[] = [];
  filteredScores: SimilarReplay[] = [];

  filterManager = new FilterManagerService<FilterStolenReplays>("stolenReplaysFilters");

  currentPage = 1;
  itemsPerPage = 100;

  getTotalPages(): number {
    return Math.ceil(this.filteredScores.length / this.itemsPerPage);
  }

  getCurrentPage(): SimilarReplay[] {
    const start = (this.currentPage - 1) * this.itemsPerPage;
    const end = start + this.itemsPerPage;
    return this.filteredScores.slice(start, end);
  }

  constructor(
    private localCacheService: LocalCacheService,
    private router: Router,
    private activatedRoute: ActivatedRoute
  ) { }

  ngOnInit(): void {
    this.activatedRoute.params.subscribe(params => {
      let filters = params['f'];
      if (filters) {
        this.filterManager.setFiltersFromUrl(filters);
        this.isUrlFilters = true;
      } else {
        this.filterManager.setFiltersFromLocal();
      }
    });

    this.getSimilarReplays().subscribe(scores => {
      this.originalScores = scores;
      this.filterScores();
      // this.isLoading = false;
    });
  }

  getSimilarReplays(): Observable<SimilarReplay[]> {
    return this.localCacheService.fetchData<SimilarReplay[]>(
      'similarReplays',
      `${environment.apiUrl}/similar-replays`,
      15
    );
  }

  getFiltersUrl(): void {
    let targetUrl = '/stolen/' + this.filterManager.getFiltersUrl();
    this.router.navigate([targetUrl]).then(() => {
      navigator.clipboard.writeText(targetUrl).then(() => {
        console.debug('Loaded filters!')
      });
    });
  }

  resetValues(): void {
    this.filterManager.resetValues();
    this.filterScores();
    this.router.navigate(['/stolen']).then(() => {
      this.isUrlFilters = false;
    });
  }

  filterScores(): void {
    const filters = this.filterManager.filters;

    // Trim and convert to lowercase for case-insensitive comparison
    const searchUsername = filters.searchUsername?.trim().toLowerCase();
    const searchBeatmap = filters.searchBeatmap?.trim().toLowerCase();

    this.filteredScores = this.originalScores.filter((score) => {
      // Apply username filter if specified, case-insensitive
      const usernameMatch = searchUsername ?
        (score.username_1.toLowerCase().includes(searchUsername) || score.username_2.toLowerCase().includes(searchUsername)) :
        true;

      // Apply beatmap filter if specified, case-insensitive
      const beatmapMatch = searchBeatmap ?
        score.beatmap_title.toLowerCase().includes(searchBeatmap) :
        true;

      // Apply PP filter if specified, checking against both replay_pp_1 and replay_pp_2
      const ppMatch = (filters.minPP !== undefined ? (score.replay_pp_1 >= filters.minPP || score.replay_pp_2 >= filters.minPP) : true) &&
        (filters.maxPP !== undefined ? (score.replay_pp_1 <= filters.maxPP || score.replay_pp_2 <= filters.maxPP) : true);


      // Apply similarity filter if specified
      const similarityMatch = (filters.minSimilarity !== undefined ? score.similarity >= filters.minSimilarity : true) &&
        (filters.maxSimilarity !== undefined ? score.similarity <= filters.maxSimilarity : true);

      return usernameMatch && beatmapMatch && ppMatch && similarityMatch;
    });

    this.filterManager.persistToLocalStorage();

    // Sort
    if(this.filterManager.filters.sorting) {
      let field = this.filterManager.filters.sorting.split("-")[0];
      let order = this.filterManager.filters.sorting.split("-")[1];
      //@ts-ignore
      this.sortScores(field, order);
    }
  }

  sortScores(field: 'replay_date_1' | 'replay_date_2' | 'similarity' | 'beatmap_star_rating', order: 'asc' | 'desc'): void {
    if(this.isUrlFilters && this.filterManager.filters.sorting != `${field}-${order}`) {
      return;
    }

    this.filterManager.filters.sorting = `${field}-${order}`
    this.filterManager.persistToLocalStorage();
    this.currentPage = 1;

    this.filteredScores.sort((a, b) => {
      let valueA: number | string;
      let valueB: number | string;

      // Assigning values based on the field
      if (field === 'replay_date_1') {
        valueA = a.replay_date_1;
        valueB = b.replay_date_1;
      } else if (field === 'replay_date_2') {
        valueA = a.replay_date_2;
        valueB = b.replay_date_2;
      } else if (field === 'similarity' || field === 'beatmap_star_rating') {
        // Direct comparison for numeric values
        valueA = a[field];
        valueB = b[field];
      } else {
        // Default case if needed
        valueA = a.similarity; // or any default field
        valueB = b.similarity; // or any default field
      }

      // Determine sorting order
      if (order === 'asc') {
        return valueA < valueB ? -1 : valueA > valueB ? 1 : 0;
      } else { // if 'desc'
        return valueA > valueB ? -1 : valueA < valueB ? 1 : 0;
      }
    });
  }

}
