"""
Module detecting numbers with too many digits.
"""

from slither.detectors.abstract_detector import AbstractDetector, DetectorClassification
from slither.slithir.variables import Constant


class TooManyDigits(AbstractDetector):
    """
    Detect numbers with too many digits
    """

    ARGUMENT = 'too-many-digits'
    HELP = 'Conformance to numeric notation best practices'
    IMPACT = DetectorClassification.INFORMATIONAL
    CONFIDENCE = DetectorClassification.MEDIUM

    WIKI = 'https://github.com/crytic/slither/wiki/Detector-Documentation#too-many-digits'
    WIKI_TITLE = 'Too many digits'
    WIKI_DESCRIPTION = '''
Literals with many digits are difficult to read and review.
'''
    WIKI_EXPLOIT_SCENARIO = '''
```solidity
contract MyContract{
    uint 1_ether = 10000000000000000000; 
}
```

While `1_ether` looks like `1 ether`, it is `10 ether`. As a result, its usage is likely to be incorrect.
'''
    WIKI_RECOMMENDATION = '''
Use:
- [Ether suffix](https://solidity.readthedocs.io/en/latest/units-and-global-variables.html#ether-units)
- [Time suffix](https://solidity.readthedocs.io/en/latest/units-and-global-variables.html#time-units), or
- [The scientific notation](https://solidity.readthedocs.io/en/latest/types.html#rational-and-integer-literals)
'''

    @staticmethod
    def _detect_too_many_digits(f):
        ret = []
        for node in f.nodes:
            # each node contains a list of IR instruction
            for ir in node.irs:
                # iterate over all the variables read by the IR
                for read in ir.read:
                    # if the variable is a constant
                    if isinstance(read, Constant):
                        # read.value can return an int or a str. Convert it to str
                        value_as_str = read.original_value
                        if '00000' in value_as_str:
                            # Info to be printed
                            ret.append(node)
        return ret

    def _detect(self):
        results = []

        # iterate over all contracts
        for contract in self.slither.contracts_derived:
        # iterate over all functions
            for f in contract.functions:
                # iterate over all the nodes
                ret = self._detect_too_many_digits(f)
                if ret:
                    func_info = [f, ' uses literals with too many digits:']
                    for node in ret:
                        node_info = func_info + ['\n\t- ', node,'\n']

                        # Add the result in result
                        res = self.generate_result(node_info)
                        results.append(res)

        return results
