// Copyright 2021 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#ifndef CHROME_BROWSER_UI_WEBUI_SIGNIN_SIGNIN_UI_ERROR_H_
#define CHROME_BROWSER_UI_WEBUI_SIGNIN_SIGNIN_UI_ERROR_H_

#include <string>
#include <utility>

#include "base/files/file_path.h"
#include "build/build_config.h"

#if BUILDFLAG(IS_WIN)
#include "chrome/credential_provider/common/gcp_strings.h"
#endif

class GoogleServiceAuthError;

// Holds different sign-in error types along with error messages for displaying
// in the UI.
class SigninUIError {
 public:
  // An error type.
  // Different types of UI might be shown for different error types.
  // LINT.IfChange(SigninUIErrorType)
  enum class Type : int {
    kOk = 0,
    kUsernameNotAllowedByPatternFromPrefs = 1,
    kWrongReauthAccount = 2,
    kAccountAlreadyUsedByAnotherProfile = 3,
    kProfileWasUsedByAnotherAccount = 4,
    kFromGoogleServiceAuthError = 5,
    kFromCredentialProviderUiExitCode = 6,
    kNoProfile = 7,
    kSigninDisallowed = 8,
    kSigninCookiesDisallowed = 9,
    kNoIdentityManager = 10,
    kMaxValue = kNoIdentityManager,
  };
  // LINT.ThenChange(//tools/metrics/histograms/metadata/profile/enums.xml:SigninUIErrorType)

  // Following static functions construct a `SigninUIError` with a corresponding
  // type and error message.
  static SigninUIError Ok();
  static SigninUIError UsernameNotAllowedByPatternFromPrefs(
      std::string_view email);
  static SigninUIError WrongReauthAccount(std::string_view email,
                                          std::string_view current_email);
  static SigninUIError AccountAlreadyUsedByAnotherProfile(
      std::string_view email,
      const base::FilePath& another_profile_path);
  static SigninUIError ProfileWasUsedByAnotherAccount(
      std::string_view email,
      std::string_view last_email);
  static SigninUIError FromGoogleServiceAuthError(
      std::string_view email,
      const GoogleServiceAuthError& error);
#if BUILDFLAG(IS_WIN)
  static SigninUIError FromCredentialProviderUiExitCode(
      std::string_view email,
      credential_provider::UiExitCodes exit_code);
#endif
  static SigninUIError NoProfile(std::string_view email);
  static SigninUIError SigninDisallowed(std::string_view email);
  static SigninUIError SigninCookiesDisallowed(std::string_view email);
  static SigninUIError NoIdentityManager(std::string_view email);

  SigninUIError(const SigninUIError& other);
  SigninUIError& operator=(const SigninUIError& other);

  // Returns true if the instance contains a non-error type.
  bool IsOk() const;

  Type type() const;
  const std::u16string& email() const;
  const std::u16string& message() const;

  // Should be called only if `type()` ==
  // `Type::kAccountAlreadyUsedByAnotherProfile`.
  const base::FilePath& another_profile_path() const;

#if BUILDFLAG(IS_WIN)
  // Should be called only if `type()` ==
  // `Type::kFromCredentialProviderUiExitCode`.
  credential_provider::UiExitCodes credential_provider_exit_code() const;
#endif

  friend bool operator==(const SigninUIError&, const SigninUIError&) = default;

 private:
  SigninUIError(Type type,
                std::string_view email,
                const std::u16string& error_message);

  Type type_;
  std::u16string email_;
  std::u16string message_;

  // Defined only for Type::kAccountAlreadyUsedByAnotherProfile.
  base::FilePath another_profile_path_;

#if BUILDFLAG(IS_WIN)
  // Defined only for Type::kFromCredentialProviderUiExitCode.
  credential_provider::UiExitCodes credential_provider_exit_code_ =
      credential_provider::UiExitCodes::kUiecSuccess;
#endif
};

// Holds different errors to be displayed through the Force Signin error dialog.
class ForceSigninUIError {
 public:
  ForceSigninUIError(const ForceSigninUIError& other);
  ForceSigninUIError& operator=(const ForceSigninUIError& other);

  enum class Type {
    kNone,
    // Reauth is not allowed for this Profile.
    kReauthNotAllowed,
    // Reauth was attempted using a different account than the main one.
    // The expected email will be shown in the error message.
    kReauthWrongAccount,
    // A timeout occurred while attempting to reauth.
    kReauthTimeout,
    // Signin pattern not matching.
    kSigninPatternNotMatching,
    // Reauth flows are not supported in Glic Mode, redirects the user to do the
    // reauth in the Regular Picker.
    kReauthNotSupportedByGlicFlow,
  };

  // Helper pair to get the error messages based on the `Type` error enum to be
  // displayed on the Profile Picker error dialog.
  // - `first` for the title/header message.
  // - `second` for the body message.
  using UiTexts = std::pair<std::u16string, std::u16string>;

  // Static constructors for each error type with the corresponding needed
  // inputs.
  static ForceSigninUIError ErrorNone();
  static ForceSigninUIError ReauthNotAllowed();
  static ForceSigninUIError ReauthWrongAccount(const std::string& email);
  static ForceSigninUIError ReauthTimeout();
  static ForceSigninUIError SigninPatternNotMatching(const std::string& email);
  static ForceSigninUIError ReauthNotSupportedByGlicFlow();

  // Returns the error messages for the given `error`.
  // `type_` must not be `ForceSigninUIError::kNone`.
  UiTexts GetErrorTexts() const;

  Type type() const;

 private:
  ForceSigninUIError(Type type, const std::string& email);

  Type type_;
  std::string email_;
};

#endif  // CHROME_BROWSER_UI_WEBUI_SIGNIN_SIGNIN_UI_ERROR_H_
