/// <summary>
        /// Handle a conflict
        /// The int returned is the conflict count I need
        /// </summary>
        /// changeApplicationAction, conflictCount, resolvedRow, conflictApplyInt
        internal async Task <(int conflictResolvedCount, SyncRow resolvedRow, int rowAppliedCount)> HandleConflictAsync(
            Guid localScopeId, Guid senderScopeId,
            DbSyncAdapter syncAdapter, SyncContext context, SyncConflict conflict,
            ConflictResolutionPolicy policy, long lastTimestamp,
            DbConnection connection, DbTransaction transaction)
        {
            SyncRow     finalRow;
            ApplyAction conflictApplyAction;
            int         rowAppliedCount = 0;

            (conflictApplyAction, finalRow) = await this.GetConflictActionAsync(context, conflict, policy, connection, transaction).ConfigureAwait(false);

            // Conflict rollbacked by user
            if (conflictApplyAction == ApplyAction.Rollback)
            {
                throw new RollbackException("Rollback action taken on conflict");
            }

            // Local provider wins, update metadata
            if (conflictApplyAction == ApplyAction.Continue)
            {
                var isMergeAction = finalRow != null;
                var row           = isMergeAction ? finalRow : conflict.LocalRow;

                // Conflict on a line that is not present on the datasource
                if (row == null)
                {
                    return(0, finalRow, 0);
                }

                // if we have a merge action, we apply the row on the server
                if (isMergeAction)
                {
                    // if merge, we update locally the row and let the update_scope_id set to null
                    var isUpdated = await syncAdapter.ApplyUpdateAsync(row, lastTimestamp, null, true);

                    // We don't update metadatas so the row is updated (on server side)
                    // and is mark as updated locally.
                    // and will be returned back to sender, since it's a merge, and we need it on the client

                    if (!isUpdated)
                    {
                        throw new Exception("Can't update the merge row.");
                    }
                }

                finalRow = isMergeAction ? row : conflict.LocalRow;

                // We don't do anything, since we let the original row. so we resolved one conflict but applied no rows
                return(conflictResolvedCount : 1, finalRow, rowAppliedCount : 0);
            }

            // We gonna apply with force the line
            if (conflictApplyAction == ApplyAction.RetryWithForceWrite)
            {
                // TODO : Should Raise an error ?
                if (conflict.RemoteRow == null)
                {
                    return(0, finalRow, 0);
                }

                bool operationComplete = false;

                switch (conflict.Type)
                {
                // Remote source has row, Local don't have the row, so insert it
                case ConflictType.RemoteExistsLocalExists:
                case ConflictType.RemoteExistsLocalNotExists:
                case ConflictType.RemoteExistsLocalIsDeleted:
                case ConflictType.UniqueKeyConstraint:
                    operationComplete = await syncAdapter.ApplyUpdateAsync(conflict.RemoteRow, lastTimestamp, senderScopeId, true);

                    rowAppliedCount = 1;
                    break;

                // Conflict, but both have delete the row, so nothing to do
                case ConflictType.RemoteIsDeletedLocalIsDeleted:
                case ConflictType.RemoteIsDeletedLocalNotExists:
                    operationComplete = true;
                    rowAppliedCount   = 0;
                    break;

                // The remote has delete the row, and local has insert or update it
                // So delete the local row
                case ConflictType.RemoteIsDeletedLocalExists:
                    operationComplete = await syncAdapter.ApplyDeleteAsync(conflict.RemoteRow, lastTimestamp, senderScopeId, true);

                    rowAppliedCount = 1;
                    break;


                case ConflictType.RemoteCleanedupDeleteLocalUpdate:
                case ConflictType.ErrorsOccurred:
                    return(0, finalRow, 0);
                }

                finalRow = conflict.RemoteRow;

                //After a force update, there is a problem, so raise exception
                if (!operationComplete)
                {
                    finalRow = null;
                    return(0, finalRow, rowAppliedCount);
                }

                return(1, finalRow, rowAppliedCount);
            }

            return(0, finalRow, 0);
        }