package io.getlime.security.powerauth.lib.dataadapter.impl.service;

import io.getlime.security.powerauth.lib.dataadapter.api.DataAdapter;
import io.getlime.security.powerauth.lib.dataadapter.exception.AuthenticationFailedException;
import io.getlime.security.powerauth.lib.dataadapter.exception.SMSAuthorizationFailedException;
import io.getlime.security.powerauth.lib.dataadapter.exception.UserNotFoundException;
import io.getlime.security.powerauth.lib.dataadapter.model.entity.*;
import io.getlime.security.powerauth.lib.dataadapter.model.response.UserDetailResponse;
import org.springframework.stereotype.Service;

import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.List;
import java.util.logging.Level;
import java.util.logging.Logger;

/**
 * Sample implementation of DataAdapter interface which should be updated in real implementation.
 *
 * @author Roman Strobl
 */
@Service
public class DataAdapterService implements DataAdapter {

    public DataAdapterService() {
    }

    @Override
    public UserDetailResponse authenticateUser(String username, String password) throws AuthenticationFailedException {
        // Here will be the real authentication - call to the backend providing authentication.
        // In case that authentication fails, throw an AuthenticationFailedException.
        if ("test".equals(password)) {
            UserDetailResponse userDetail = new UserDetailResponse();
            // Set real user ID.
            userDetail.setId("12345678");
            // Provide real user details as long as they are available.
            userDetail.setGivenName("John");
            userDetail.setFamilyName("Doe");
            return userDetail;
        }
        throw new AuthenticationFailedException("login.authenticationFailed");
    }

    @Override
    public UserDetailResponse fetchUserDetail(String userId) throws UserNotFoundException {
        // Fetch user details here ...
        // In case that user is not found, throw a UserNotFoundException.
        UserDetailResponse responseObject = new UserDetailResponse();
        responseObject.setId(userId);
        responseObject.setGivenName("John");
        responseObject.setFamilyName("Doe");
        return responseObject;
    }

    @Override
    public List<BankAccount> fetchBankAccounts(String userId) throws UserNotFoundException {
        // Fetch bank account list for given user here from the bank backend.
        // In case that user is not found, throw a UserNotFoundException.
        // Replace mock bank account data with real data loaded from the bank backend.
        // In case the bank account selection is disabled, return an empty list.
        List<BankAccount> bankAccounts = new ArrayList<>();

        BankAccount bankAccount1 = new BankAccount();
        bankAccount1.setName("Běžný účet v CZK");
        bankAccount1.setBalance(new BigDecimal("24394.52"));
        bankAccount1.setNumber("12345678/1234");
        bankAccount1.setCurrency("CZK");
        bankAccount1.setUsableForPayment(true);
        bankAccounts.add(bankAccount1);

        BankAccount bankAccount2 = new BankAccount();
        bankAccount2.setName("Spořící účet v CZK");
        bankAccount2.setBalance(new BigDecimal("158121.10"));
        bankAccount2.setNumber("87654321/4321");
        bankAccount2.setCurrency("CZK");
        bankAccount2.setUsableForPayment(true);
        bankAccounts.add(bankAccount2);

        BankAccount bankAccount3 = new BankAccount();
        bankAccount3.setName("Spořící účet v EUR");
        bankAccount3.setBalance(new BigDecimal("1.90"));
        bankAccount3.setNumber("44444444/1111");
        bankAccount3.setCurrency("EUR");
        bankAccount3.setUsableForPayment(false);
        bankAccount3.setUnusableForPaymentReason("operationReview.balanceTooLow");
        bankAccounts.add(bankAccount3);

        return bankAccounts;
    }

    @Override
    public void formDataChangedNotification(String userId, String operationId, FormDataChange change) {
        switch (change.getType()) {
            case BANK_ACCOUNT_CHOICE:
                // Handle bank account choice here (e.g. send notification to bank backend).
                BankAccountChoice bankAccountChoice = (BankAccountChoice) change;
                Logger.getLogger(this.getClass().getName()).log(Level.INFO, "Bank account chosen: " + bankAccountChoice.getBankAccountNumber() + ", user: " + userId + ", operationId: " + operationId);
                break;
            case AUTH_METHOD_CHOICE:
                // Handle authorization method choice here (e.g. send notification to bank backend).
                AuthMethodChoice authMethodChoice = (AuthMethodChoice) change;
                Logger.getLogger(this.getClass().getName()).log(Level.INFO, "Authorization method chosen: " + authMethodChoice.getChosenAuthMethod() + ", user: " + userId + ", operationId: " + operationId);
                break;
            default:
                throw new IllegalStateException("Invalid change entity type: " + change.getType());
        }
    }

    @Override
    public void operationChangedNotification(String userId, String operationId, OperationChange change) {
        // Handle operation change here (e.g. send notification to bank backend).
        Logger.getLogger(this.getClass().getName()).log(Level.INFO, "Operation changed: " + change + ", user: " + userId + ", operationId: " + operationId);
    }

    @Override
    public void sendAuthorizationSMS(String userId, String messageText) throws SMSAuthorizationFailedException {
        // Add here code to send the SMS OTP message to user identified by userId with messageText.
        // In case message delivery fails, throw an SMSAuthorizationFailedException.
    }

}

@@ -1371,299 +1371,195 @@
     
-UserDetailResponse userDetail = new UserDetailResponse();%0A            // Set real user ID.%0A            userDetail.setId(%2212345678%22);%0A            // Provide real user details as long as they are available.%0A            userDetail.setGivenName(%22John%22);%0A            userDetail.set
+try %7B%0A                return fetchUserDetail(username);%0A            %7D catch (UserNotFoundException e) %7B%0A                throw new AuthenticationFailedException(%22login.authentication
 Fa
-m
 il
-yName(%22Do
 e
+d
 %22);%0A
@@ -1574,26 +1574,9 @@
     
-return userDetail;
+%7D
 %0A   

Fix #134: Default implementation of Data Adapter user authentication should return same userId as username