C# Update account based on user order data. Nested if-else optimization with almost similar values The method works, but I would like to know if there is any way to make it more readable, optimized?
I have user data (i want to import/update it).
Accounts is finded by user data.
========
User order data is entered into the system.
userData.Id - user Id; userData.OrderNumber - user order number.
The &quot;UpdateAccount&quot; method below is used by the user.
The user enters their Id and OrderNumber into the system (there are FirstName, LastName, etc., but they are irrelevant here because they are used in the UpdateAllUserDataToAccount method).
Therefore, it is necessary to discover whether an account with the relevant data exists in the system.
You can update account data if the account has userData.OrderNumber or userData.Id.
If no account under userData.OrderNumber or userData.Id is found in the system then create a new account and update its data.
Do not allow anything if userData.OrderNumber, userData.Id is in different account (can not exist in the system in different account).
An account can have userData.OrderNumber in the system and not userData.Id because the employee registered the parcel but did not have a user id.
An account can have userData.Id in the system and not userData.OrderNumber because the user has previously been registered in the system.
The user data userData.OrderNumber and userData.Id are unique and belong to only one user.
bool _isSpecialData - to indicate that the user is special (set before this code).
private void UpdateAccount(UserModel userData)
{               
    Account accountById = _accountController.GetAccountById(userData.Id);
    Account accountByNumber = _accountController.GetAccountByNumber(userData.Number);
    bool _isSpecialData = accountByNumber != null ? accountByNumber.Vip : false;
    
    if (accountById != null)
    {
        if (accountByNumber != null)
        {
            if (accountById.Id == accountByNumber.Id)
            {
                if (_isSpecialData)
                {
                    AddPartUserDataToAccount(userData, accountByNumber);

                    if (userData.Status == Blocked) return;
                }
            }
            else
            {
                _log.Error($&quot;User data can not be in different accounts&quot;);
                return;
            }
        }
        else
        {
            AddPartUserDataToAccount(userData, accountById);
        }
    }
    else
    {
        if (accountByNumber != null)
        {
            if (accountByNumber.Id == null)
            {                            
                accountByNumber.Id = userData.Id;

                if (_isSpecialData)
                {
                    AddPartUserDataToAccount(userData, accountByNumber);
                    if (userData.Status == Blocked) return;
                }
            }
            else
            {
                _log.Error($&quot;accountByNumber.Id can be just with the same value as userData.Id or with null (because it was not set in first place)&quot;);
                return;
            }
        }
        else
        {
            CreateNewAccount(userData);
        }
    }
                
    UpdateAllUserDataToAccount(userData);
}
This code is hard to read, deeply nested and hard to understand. But you already know that.
Since you have a lot of binary cases (if-else) I suggest creating a truth table
on paper or whiteboard https://en.wikipedia.org/wiki/Truth_table#Binary_operations for your different combinations of input and output.
This should help you figure out which cases can be simplified, short-circuit, etc, and then you can rewrite the code to make it more readable. Use early returns and maybe refactor it into functions that allow you to check error conditions and return/exit as soon as possible for each case.
The end goal should be a code structure that doesn't nest 4 5 levels deep, preferrably no more than 2.