// Copyright (C) 2022 WYATT GROUP
// Please see the AUTHORS file for details.
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>.

import 'package:wyatt_architecture/wyatt_architecture.dart';
import 'package:wyatt_authentication_bloc/src/domain/entities/account.dart';
import 'package:wyatt_authentication_bloc/src/domain/entities/account_wrapper.dart';
import 'package:wyatt_form_bloc/wyatt_form_bloc.dart';

abstract class AuthenticationRepository<T> extends BaseRepository {
  FormRepository get formRepository;

  /// {@template signup}
  /// Creates a new user with the provided [email] and [password].
  ///
  /// Returns the newly created user's unique identifier.
  ///
  /// Throws a SignUpWithEmailAndPasswordFailureInterface if
  /// an exception occurs.
  /// {@endtemplate}
  FutureOrResult<Account> signUp({
    required String email,
    required String password,
  });

  /// {@template send_email_verification}
  /// Sends verification email to the account email.
  ///
  /// Throws a SendEmailVerificationFailureInterface if an exception occurs.
  /// {@endtemplate}
  FutureOrResult<void> sendEmailVerification();

  /// {@template send_password_reset_email}
  /// Sends a password reset email to the provided [email].
  ///
  /// Throws a SendPasswordResetEmailFailureInterface if an exception occurs.
  /// {@endtemplate}
  FutureOrResult<void> sendPasswordResetEmail({required String email});

  /// {@template confirm_password_reset}
  /// Confirms the password reset with the provided [newPassword] and [code].
  ///
  /// Throws a ConfirmPasswordResetFailureInterface if an exception occurs.
  /// {@endtemplate}
  FutureOrResult<void> confirmPasswordReset({
    required String code,
    required String newPassword,
  });

  /// {@template verify_password_reset_code}
  /// Verify password reset code.
  ///
  /// Throws a VerifyPasswordResetCodeFailureInterface if an exception occurs.
  /// {@endtemplate}
  FutureOrResult<bool> verifyPasswordResetCode({required String code});

  /// {@template signin_anom}
  /// Sign in anonymously.
  ///
  /// Throws a SignInAnonymouslyFailureInterface if an exception occurs.
  /// {@endtemplate}
  FutureOrResult<Account> signInAnonymously();

  /// {@template signin_google}
  /// Starts the Sign In with Google Flow.
  ///
  /// Throws a SignInWithGoogleFailureInterface if an exception occurs.
  /// {@endtemplate}
  FutureOrResult<Account> signInWithGoogle();

  /// {@template signin_pwd}
  /// Signs in with the provided [email] and [password].
  ///
  /// Throws a SignInWithEmailAndPasswordFailureInterface if
  /// an exception occurs.
  /// {@endtemplate}
  FutureOrResult<Account> signInWithEmailAndPassword({
    required String email,
    required String password,
  });

  /// {@template update_email}
  /// Update or add [email].
  ///
  /// Throws a UpdateEmailFailureInterface if
  /// an exception occurs.
  /// {@endtemplate}
  FutureOrResult<Account> updateEmail({
    required String email,
  });

  /// {@template update_password}
  /// Update or add [password].
  ///
  /// Throws a UpdatePasswordFailureInterface if
  /// an exception occurs.
  /// {@endtemplate}
  FutureOrResult<Account> updatePassword({
    required String password,
  });

  /// {@template reauthenticate}
  /// Some security-sensitive actions—such as deleting an account,
  /// setting a primary email address, and changing a password—require that
  /// the user has recently signed in.
  ///
  /// Throws a ReauthenticateFailureInterface if
  /// an exception occurs.
  /// {@endtemplate}
  FutureOrResult<Account> reauthenticateWithCredential();

  /// {@template signout}
  /// Signs out the current user.
  /// It also clears the cache and the associated data.
  /// {@endtemplate}
  FutureOrResult<void> signOut();

  /// {@template refresh}
  /// Refreshes the current user, if signed in.
  /// {@endtemplate}
  FutureOrResult<void> refresh();

  /// {@template stream_account}
  /// Stream of [AccountWrapper] which will emit the current account when
  /// the authentication state changes.
  ///
  /// Emits [AccountWrapper] with null [Account] if the user is not
  /// authenticated.
  /// {@endtemplate}
  Stream<FutureOrResult<AccountWrapper<T>>> streamAccount();

  FutureOrResult<String> getIdentityToken();

  FutureOrResult<Account> getAccount();
  FutureOrResult<void> setAccount(Account account);

  FutureOrResult<T> getData();
  FutureOrResult<void> setData(T? data);

  FutureOrResult<AccountWrapper<T>> getCache();
  FutureOrResult<void> destroyCache();
}
