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

#import "ios/chrome/app/profile/post_restore_profile_agent.h"

#import "base/memory/raw_ptr.h"
#import "components/signin/public/base/consent_level.h"
#import "components/signin/public/identity_manager/identity_manager.h"
#import "components/signin/public/identity_manager/objc/identity_manager_observer_bridge.h"
#import "ios/chrome/app/profile/profile_init_stage.h"
#import "ios/chrome/app/profile/profile_state.h"
#import "ios/chrome/app/profile/profile_state_observer.h"
#import "ios/chrome/browser/promos_manager/model/constants.h"
#import "ios/chrome/browser/promos_manager/model/promos_manager.h"
#import "ios/chrome/browser/promos_manager/model/promos_manager_factory.h"
#import "ios/chrome/browser/shared/model/profile/profile_ios.h"
#import "ios/chrome/browser/signin/model/authentication_service.h"
#import "ios/chrome/browser/signin/model/authentication_service_factory.h"
#import "ios/chrome/browser/signin/model/identity_manager_factory.h"
#import "ios/chrome/browser/signin/model/signin_util.h"

@interface PostRestoreProfileAgent () <IdentityManagerObserving>
@end

@implementation PostRestoreProfileAgent {
  // The identity manager.
  raw_ptr<signin::IdentityManager> _identityManager;
  std::unique_ptr<signin::IdentityManagerObserverBridge>
      _identityObserverBridge;

  // The PromosManager used to register promos.
  raw_ptr<PromosManager> _promosManager;

  // Profile pref service used to retrieve and/or clear the pre-restore
  // identity.
  raw_ptr<PrefService> _prefService;

  // Stores whether we have pre-restore account info.
  BOOL _hasAccountInfo;
}

#pragma mark - ProfileStateObserver

- (void)profileState:(ProfileState*)profileState
    didTransitionToInitStage:(ProfileInitStage)nextInitStage
               fromInitStage:(ProfileInitStage)fromInitStage {
  if (nextInitStage != ProfileInitStage::kFinal) {
    return;
  }

  DCHECK(profileState.profile);
  ProfileIOS* profile = profileState.profile;
  _promosManager = PromosManagerFactory::GetForProfile(profile);
  _identityManager = IdentityManagerFactory::GetForProfile(profile);
  _identityObserverBridge =
      std::make_unique<signin::IdentityManagerObserverBridge>(_identityManager,
                                                              self);
  _prefService = profile->GetPrefs();
  _hasAccountInfo = GetPreRestoreIdentity(_prefService).has_value();
  // TODO(crbug.com/442982538): This dialog should be skipped if sign-in is
  // disabled.
  [self maybeRegisterPromo];
  if (!_hasAccountInfo) {
    [self shutdown];
  }
}

#pragma mark - IdentityManagerObserving

// Called when a user adds a primary account.
- (void)primaryAccountDidChange:
    (const signin::PrimaryAccountChangeEvent&)event {
  switch (event.GetEventTypeFor(signin::ConsentLevel::kSignin)) {
    case signin::PrimaryAccountChangeEvent::Type::kSet:
      if (_promosManager) {
        [self deregisterPromos];
        ClearPreRestoreIdentity(_prefService);
        _hasAccountInfo = NO;
        [self shutdown];
      }
      break;
    case signin::PrimaryAccountChangeEvent::Type::kCleared:
    case signin::PrimaryAccountChangeEvent::Type::kNone:
      break;
  }
}

- (void)identityManagerDidShutdown:(signin::IdentityManager*)identityManager {
  [self shutdown];
}

#pragma mark - Private

// Register the promo with the PromosManager, if the conditions are met,
// otherwise deregister the promo.
- (void)maybeRegisterPromo {
  if (_promosManager && _hasAccountInfo) {
    [self registerPromo];
  } else if (_promosManager) {
    [self deregisterPromos];
  } else if (_hasAccountInfo) {
    ClearPreRestoreIdentity(_prefService);
  }
}

// Registers the promo with the PromosManager.
- (void)registerPromo {
  DCHECK(_promosManager);
  DCHECK(self.profileState.profile);
  // Disable the reauth infobar so that we don't prompt the user twice about
  // reauthenticating.
  AuthenticationServiceFactory::GetForProfile(self.profileState.profile)
      ->ResetReauthPromptForSignInAndSync();

  // Deregister any previously registered promos.
  [self deregisterPromos];
  _promosManager->RegisterPromoForSingleDisplay(
      promos_manager::Promo::PostRestoreSignInAlert);
}

// Deregisters the promo with the PromosManager.
- (void)deregisterPromos {
  DCHECK(_promosManager);
  _promosManager->DeregisterPromo(
      promos_manager::Promo::PostRestoreSignInFullscreen);
  _promosManager->DeregisterPromo(
      promos_manager::Promo::PostRestoreSignInAlert);
}

// Stops observers and clears pointers.
- (void)shutdown {
  [self.profileState removeAgent:self];
  _promosManager = nullptr;
  _identityManager = nullptr;
  _identityObserverBridge.reset();
}

@end
