//
// Copyright 2025 Element Creations Ltd.
// Copyright 2022-2025 New Vector Ltd.
//
// SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial.
// Please see LICENSE files in the repository root for full details.
//

@testable import ElementX
import Foundation
import Testing

@MainActor
@Suite
struct DeactivateAccountScreenViewModelTests {
    var clientProxy: ClientProxyMock!
    var viewModel: DeactivateAccountScreenViewModelProtocol!
    
    var context: DeactivateAccountScreenViewModelType.Context {
        viewModel.context
    }
    
    init() {
        clientProxy = ClientProxyMock(.init())
        viewModel = DeactivateAccountScreenViewModel(clientProxy: clientProxy, userIndicatorController: UserIndicatorControllerMock())
    }
    
    @Test
    mutating func deactivate() async throws {
        try await validateDeactivate(erasingData: false)
    }
    
    @Test
    mutating func deactivateAndErase() async throws {
        try await validateDeactivate(erasingData: true)
    }
    
    mutating func validateDeactivate(erasingData shouldErase: Bool) async throws {
        let enteredPassword = UUID().uuidString
        
        clientProxy.deactivateAccountPasswordEraseDataClosure = { [weak clientProxy] password, eraseData in
            guard let clientProxy else { return .failure(.sdkError(ClientProxyMockError.generic)) }
            
            if clientProxy.deactivateAccountPasswordEraseDataCallsCount == 1 {
                #expect(password == nil, "The password shouldn't be sent first time round.")
                #expect(eraseData == shouldErase, "The erase parameter is unexpected.")
                return .failure(.sdkError(ClientProxyMockError.generic))
            } else {
                #expect(password == enteredPassword, "The password should match the user's input on the second call.")
                #expect(eraseData == shouldErase, "The erase parameter is unexpected.")
                return .success(())
            }
        }
        
        context.eraseData = shouldErase
        context.password = enteredPassword
        
        #expect(context.alertInfo == nil)
        
        let deferredState = deferFulfillment(context.observe(\.viewState.bindings.alertInfo)) { $0 != nil }
        context.send(viewAction: .deactivate)
        try await deferredState.fulfill()
        
        let confirmationAction = try #require(context.alertInfo?.primaryButton.action,
                                              "Couldn't find the confirmation action.")
        
        let deferredAction = deferFulfillment(viewModel.actionsPublisher) { $0 == .accountDeactivated }
        confirmationAction()
        try await deferredAction.fulfill()
        
        #expect(clientProxy.deactivateAccountPasswordEraseDataCallsCount == 2)
        #expect(clientProxy.deactivateAccountPasswordEraseDataReceivedArguments?.password == enteredPassword)
        #expect(clientProxy.deactivateAccountPasswordEraseDataReceivedArguments?.eraseData == shouldErase)
    }
}
