import { Injectable } from '@angular/core';
import {
  Firestore,
  orderBy,
  onSnapshot,
  doc,
  where,
  getDocs,
  getDoc,
  setDoc,
  addDoc,
} from '@angular/fire/firestore';
import { BehaviorSubject, Observable, take } from 'rxjs';
import { collection, query } from 'firebase/firestore';
import { RankedUser, User } from '../auth/model/user.model';
import { Games } from './score-table/score-table.component';
import { AuthService } from '../auth/authService/auth.service';
import { UserService } from '../user-profile/user.service';
import { NotifierService } from '../shared/notifierService/notifier.service';
import { Router } from '@angular/router';

@Injectable({
  providedIn: 'root',
})
export class ScoreTableService {
  private showUserGamesSubject = new BehaviorSubject<boolean>(false);
  showUserGames$ = this.showUserGamesSubject.asObservable();

  constructor(
    private firestore: Firestore,
    private authService: AuthService,
    private userService: UserService,
    private notifierService: NotifierService,
    private router: Router
  ) {}

  setShowUserGames(value: boolean) {
    this.showUserGamesSubject.next(value);
  }

  getTopUsers(): Observable<RankedUser[]> {
    return new Observable<RankedUser[]>((observer) => {
      const usersCollection = collection(this.firestore, 'users');
      const scoreQuery = query(
        usersCollection,
        where('wins', '>', 0),
        orderBy('wins', 'desc')
      );
      const unsubscribe = onSnapshot(
        scoreQuery,
        (querySnapshot) => {
          const users: RankedUser[] = [];
          querySnapshot.forEach((doc) => {
            users.push({ uid: doc.id, ...doc.data() } as RankedUser);
          });

          // Assign ranks to users
          const rankedUsers = this.assignRanks(users);
          observer.next(rankedUsers);
        },
        (error) => {
          observer.error(error);
        }
      );

      // Unsubscribe when the observer unsubscribes
      return () => unsubscribe();
    });
  }

  private assignRanks(users: RankedUser[]): RankedUser[] {
    if (users.length === 0) return users;

    let currentRank = 1;
    let previousWins = users[0].wins ?? 0; // Default to 0 if wins is null or undefined
    users[0].rank = currentRank;

    for (let i = 1; i < users.length; i++) {
      const currentWins = users[i].wins ?? 0; // Default to 0 if wins is null or undefined
      if (currentWins < previousWins) {
        currentRank++;
      }
      users[i].rank = currentRank;
      previousWins = currentWins;
    }

    return users;
  }

  validateAndAddGame(score: string, uid: string) {
    this.authService.currentUser$.pipe(take(1)).subscribe((user) => {
      if (user) {
        const qrCodeRef = doc(this.firestore, 'qrCodes', uid);
        getDoc(qrCodeRef).then((qrCodeDoc) => {
          const usedBy =
            qrCodeDoc.exists() && qrCodeDoc.data()['usedBy']
              ? qrCodeDoc.data()['usedBy']
              : [];

          let message = usedBy.includes(user.uid)
            ? 'Dieses Spiel wurde bereits zu deinem Konto hinzugefügt!'
            : usedBy.length >= 2
            ? 'Dieser QR-Code ist nicht mehr gültig!'
            : null;

          if (!message) {
            const updatedUsedBy = [...usedBy, user.uid];
            setDoc(qrCodeRef, { usedBy: updatedUsedBy }, { merge: true }).then(
              () => {
                this.addGameToDatabase(score, user.uid);
              }
            );
          } else {
            this.router.navigate(['/score-table']);
            this.notifierService.showNotification(message, 'OK');
          }
        });
      }
    });
  }

  addGameToDatabase(score: string, userId: string) {
    const userRef = doc(this.firestore, 'users', userId);
    const game = {
      score: score,
      date: new Date(),
      userRef: userRef,
    };
    const gamesRef = collection(this.firestore, 'games');

    addDoc(gamesRef, game)
      .then(() => {
        this.userService.updateUserWins(userId).subscribe(); // Update the user's wins count
      })
      .finally(() => {
        this.router.navigate(['/score-table']);
        this.notifierService.showNotification(
          'Spiel erfolgreich zu deinem Konto hinzugefügt!',
          'OK'
        );
      });
  }

  async loadUserGames(userId: string): Promise<Games[]> {
    const gamesRef = collection(this.firestore, 'games');
    const q = query(
      gamesRef,
      where('userRef', '==', doc(this.firestore, 'users', userId)),
      orderBy('date', 'desc')
    );

    const querySnapshot = await getDocs(q);
    const gamesArray: Games[] = querySnapshot.docs.map((doc) => {
      const score = doc.data()['score'].split('-');
      const scoreTransformed = (
        score[0].length == 1 ? '0'.concat(score[0]) : score[0]
      )
        .concat(' - ')
        .concat(score[1].length == 1 ? '0'.concat(score[1]) : score[1]);
      const dateTime: Date = doc.data()['date'].toDate();

      // Format the date and time as per the new requirements
      const formattedDate = dateTime.toLocaleDateString('de-DE', {
        day: '2-digit',
        month: '2-digit',
        year: '2-digit',
      });
      const formattedTime = dateTime.toLocaleTimeString('de-DE', {
        hour: '2-digit',
        minute: '2-digit',
        hour12: false,
      });

      return {
        id: doc.id,
        ...doc.data(),
        score: scoreTransformed,
        // Combine the formatted date and time
        date: `${formattedDate} ${formattedTime}`,
      };
    });

    return gamesArray;
  }
}
