There is no upper limit on complexity or data storage but there are constraints to be aware of.
The main constraint is maximum transaction gas cost a.k.a. block gasLimit, which is a variable network property voted on by the miners. This is an upper bound on the computational complexity of a single atomic transaction. Implicitly, this is a limit on the maximum size of a contract that can be deployed in one gulp.
It can be useful to break up large contracts into systems of smaller contracts that interact to ensure no single component is too large to deploy. As Marco pointed out, you can (and should) strictly control access to each component.
While there is no upper limit on the amount of data that is stored in a contract's state, there are two factors to keep in your top-of-mind.
- Avoid iterative processes. You need to ensure that gas cost for all interactions is scale-invariant. See here: Are there well-solved and simple storage patterns for Solidity? and here: https://blog.b9lab.com/getting-loopy-with-solidity-1d51794622ad
- Remember that the system is financially constrained. The dataset can be as large as you and your users are willing to finance. So, while it's theoretically possible to fill mappings and arrays with massive amounts of data, affordability tells another story.
Also worth keeping in mind is the idea of amortization of work. I believe that phrase was first put forward by Nick Johnson (reference in the articles linked above). Basically, there is no limit to the complexity of a state transition if it is modeled as multiple smaller atomic transactions, but each atomic transaction must always complete within the gas limit.
Hope it helps.