# Common utils for the several housekeeping scripts.

import os
import re
import collections

import logging as log
log.basicConfig(level=log.INFO, format='%(levelname)s: %(message)s')

Lint = collections.namedtuple('Lint', 'name level doc sourcefile group')
Config = collections.namedtuple('Config', 'name ty doc default')

lintname_re = re.compile(r'''pub\s+([A-Z_][A-Z_0-9]*)''')
group_re = re.compile(r'''\s*([a-z_][a-z_0-9]+)''')
conf_re = re.compile(r'''define_Conf! {\n([^}]*)\n}''', re.MULTILINE)
confvar_re = re.compile(
    r'''/// Lint: ([\w,\s]+)\. (.*)\n\s*\([^,]+,\s+"([^"]+)":\s+([^,]+),\s+([^\.\)]+).*\),''', re.MULTILINE)
comment_re = re.compile(r'''\s*/// ?(.*)''')

lint_levels = {
    "correctness": 'Deny',
    "style": 'Warn',
    "complexity": 'Warn',
    "perf": 'Warn',
    "restriction": 'Allow',
    "pedantic": 'Allow',
    "nursery": 'Allow',
    "cargo": 'Allow',
}


def parse_lints(lints, filepath):
    comment = []
    clippy = False
    deprecated = False
    name = ""

    with open(filepath) as fp:
        for line in fp:
            if clippy or deprecated:
                m = lintname_re.search(line)
                if m:
                    name = m.group(1).lower()
                    line = next(fp)

                    if deprecated:
                        level = "Deprecated"
                        group = "deprecated"
                    else:
                        while True:
                            g = group_re.search(line)
                            if g:
                                group = g.group(1).lower()
                                level = lint_levels.get(group, None)
                                break
                            line = next(fp)

                    if level is None:
                        continue

                    log.info("found %s with level %s in %s",
                             name, level, filepath)
                    lints.append(Lint(name, level, comment, filepath, group))
                    comment = []

                    clippy = False
                    deprecated = False
                    name = ""
                else:
                    m = comment_re.search(line)
                    if m:
                        comment.append(m.group(1))
            elif line.startswith("declare_clippy_lint!"):
                clippy = True
                deprecated = False
            elif line.startswith("declare_deprecated_lint!"):
                clippy = False
                deprecated = True
            elif line.startswith("declare_lint!"):
                import sys
                print(
                    "don't use `declare_lint!` in Clippy, "
                    "use `declare_clippy_lint!` instead"
                )
                sys.exit(42)


def parse_configs(path):
    configs = {}
    with open(os.path.join(path, 'utils/conf.rs')) as fp:
        contents = fp.read()

    match = re.search(conf_re, contents)
    confvars = re.findall(confvar_re, match.group(1))

    for (lints, doc, name, ty, default) in confvars:
        for lint in lints.split(','):
            configs[lint.strip().lower()] = Config(name.replace("_", "-"), ty, doc, default)
    return configs


def parse_all(path="clippy_lints/src"):
    lints = []
    for root, dirs, files in os.walk(path):
        for fn in files:
            if fn.endswith('.rs'):
                parse_lints(lints, os.path.join(root, fn))

    log.info("got %s lints", len(lints))

    configs = parse_configs(path)
    log.info("got %d configs", len(configs))

    return lints, configs