import { Injectable } from '@angular/core';
import { Observable, catchError, from, map, throwError } from 'rxjs';
import {
  Auth,
  authState,
  createUserWithEmailAndPassword,
  signInWithEmailAndPassword,
  sendEmailVerification,
  sendPasswordResetEmail,
  sendSignInLinkToEmail,
  isSignInWithEmailLink,
  signInWithEmailLink,
} from '@angular/fire/auth';
import { AuthErrorCodes } from 'firebase/auth';
import { NotifierService } from '../../shared/notifierService/notifier.service';
import { User } from '../model/user.model';
import { PendingActionsService } from '../../score/pending-actions.service';
import { UserService } from '../../user-profile/user.service';
import { Router } from '@angular/router';

@Injectable({
  providedIn: 'root',
})
export class AuthService {
  currentUser$ = authState(this.auth);

  constructor(
    private auth: Auth,
    private notifierService: NotifierService,
    private pendingService: PendingActionsService,
    private router: Router
  ) {}

  reloadUserUntilVerified() {
    const interval = setInterval(async () => {
      const user = this.getCurrentUser();
      if (user) {
        await user.reload();
        if (user.emailVerified) {
          clearInterval(interval);
        }
      }
    }, 5000);
  }

  login(username: string, password: string) {
    return from(signInWithEmailAndPassword(this.auth, username, password)).pipe(
      catchError((error) => {
        let errorMessage = 'Ein unbekannter Fehler ist aufgetreten.';
        if (error.code === AuthErrorCodes.INVALID_LOGIN_CREDENTIALS) {
          errorMessage = 'Email oder Passwort ungültig.';
        }
        return throwError(() => new Error(errorMessage));
      })
    );
  }

  loginWithEmail(): Observable<User> {
    if (isSignInWithEmailLink(this.auth, window.location.href)) {
      let email = window.localStorage.getItem('emailForSignIn');
      if (!email) {
        email = window.prompt('Please provide your email for confirmation');
      }
      if (email) {
        const [firstName, lastName] = this.extractNamesFromEmail(email);
        return from(
          signInWithEmailLink(this.auth, email, window.location.href).then(
            (result: any) => {
              window.localStorage.removeItem('emailForSignIn');
              const newUser: User = {
                uid: result.user.uid,
                email: email,
                firstName: firstName,
                lastName: lastName,
                firmenposition: null,
                photoUrl: null,
                wins: null,
              };
              this.pendingService.addUserRefToQRCodeData(
                newUser.uid,
                this.pendingService.getTempQRId()
              );
              return newUser;
            }
          )
        ).pipe(
          catchError((error) => {
            let errorMessage = 'Ein unbekannter Fehler ist aufgetreten.';
            if (error.code === AuthErrorCodes.EMAIL_EXISTS) {
              errorMessage = 'Diese E-Mail-Adresse existiert bereits.';
            }
            return throwError(() => new Error(errorMessage));
          })
        );
      }
    }
    return throwError(() => new Error('Kein Link zum Anmelden gefunden.'));
  }

  logout() {
    return from(this.auth.signOut());
  }

  signUp(email: string, score?: string, uid?: string) {
    let finishSignUpUrl = '/finish-signup';
    if (score && uid) {
      finishSignUpUrl += `?score=${score}&uid=${uid}`;
    }
    console.log('finishSignUpUrl=', finishSignUpUrl);

    const actionCodeSettings = {
      url: window.location.origin + finishSignUpUrl,
      handleCodeInApp: true,
    };

    sendSignInLinkToEmail(this.auth, email, actionCodeSettings)
      .then(() => {
        window.localStorage.setItem('emailForSignIn', email);
      })
      .catch((error) => {
        let errorMessage = 'Ein unbekannter Fehler ist aufgetreten.';
        if (error.code === AuthErrorCodes.EMAIL_EXISTS) {
          errorMessage = 'Diese E-Mail-Adresse existiert bereits.';
        }
        return throwError(() => new Error(errorMessage));
      });
  }

  signUpPassword(email: string, password: string) {
    return from(
      createUserWithEmailAndPassword(this.auth, email, password)
    ).pipe(
      map((userCredential) => {
        // Send verification email after successful sign up
        this.sendVerificationEmail();
        return userCredential;
      }),
      catchError((error) => {
        let errorMessage = 'Ein unbekannter Fehler ist aufgetreten.';
        if (error.code === AuthErrorCodes.EMAIL_EXISTS) {
          errorMessage = 'Diese E-Mail-Adresse existiert bereits.';
        }
        return throwError(() => new Error(errorMessage));
      })
    );
  }

  getCurrentUser() {
    return this.auth.currentUser;
  }

  resetPassword(email: string) {
    return sendPasswordResetEmail(this.auth, email);
  }

  get isVerifiedUser$(): Observable<boolean> {
    return this.currentUser$.pipe(
      map((user) => (user ? user.emailVerified : false))
    );
  }

  sendVerificationEmail() {
    sendEmailVerification(this.getCurrentUser()!, {
      url: window.location.origin + '/email-verification',
    }).catch((error) => {
      this.notifierService.showNotification(
        'Zu viele Versuche. Bitte probiere es später noch einmal.',
        'OK'
      );
    });
  }

  private extractNamesFromEmail(email: string): [string, string] {
    const sanitizedEmail = email.replace(/.\d|\.external/g, '');
    const [fullName] = sanitizedEmail.split('@');
    const names = fullName.split('.');

    // Vor- und Nachname grossgeschrieben
    const capitalize = (name: string) =>
      name
        .split('-')
        .map(
          (part) => part.charAt(0).toUpperCase() + part.slice(1).toLowerCase()
        )
        .join('-');

    // Capitalize both the first name and last name parts
    const firstName = names.length > 0 ? capitalize(names[0]) : '';
    const lastName =
      names.length > 1 ? capitalize(names.slice(1).join('-')) : '';

    return [firstName, lastName];
  }
}
