import codecs
import json
import locale
import os
import platform
import struct
import subprocess
import sys
from typing import List, Optional, Tuple, Union

from pandas.compat._optional import VERSIONS, _get_version, import_optional_dependency


def get_sys_info() -> List[Tuple[str, Optional[Union[str, int]]]]:
    """
    Returns system information as a list
    """
    blob: List[Tuple[str, Optional[Union[str, int]]]] = []

    # get full commit hash
    commit = None
    if os.path.isdir(".git") and os.path.isdir("pandas"):
        try:
            pipe = subprocess.Popen(
                'git log --format="%H" -n 1'.split(" "),
                stdout=subprocess.PIPE,
                stderr=subprocess.PIPE,
            )
            so, serr = pipe.communicate()
        except (OSError, ValueError):
            pass
        else:
            if pipe.returncode == 0:
                commit = so.decode("utf-8").strip().strip('"')

    blob.append(("commit", commit))

    try:
        (sysname, nodename, release, version, machine, processor) = platform.uname()
        blob.extend(
            [
                ("python", ".".join(map(str, sys.version_info))),
                ("python-bits", struct.calcsize("P") * 8),
                ("OS", f"{sysname}"),
                ("OS-release", f"{release}"),
                # ("Version", "{version}".format(version=version)),
                ("machine", f"{machine}"),
                ("processor", f"{processor}"),
                ("byteorder", f"{sys.byteorder}"),
                ("LC_ALL", f"{os.environ.get('LC_ALL', 'None')}"),
                ("LANG", f"{os.environ.get('LANG', 'None')}"),
                ("LOCALE", ".".join(map(str, locale.getlocale()))),
            ]
        )
    except (KeyError, ValueError):
        pass

    return blob


def show_versions(as_json=False):
    sys_info = get_sys_info()
    deps = [
        "pandas",
        # required
        "numpy",
        "pytz",
        "dateutil",
        # install / build,
        "pip",
        "setuptools",
        "Cython",
        # test
        "pytest",
        "hypothesis",
        # docs
        "sphinx",
        # Other, need a min version
        "blosc",
        "feather",
        "xlsxwriter",
        "lxml.etree",
        "html5lib",
        "pymysql",
        "psycopg2",
        "jinja2",
        # Other, not imported.
        "IPython",
        "pandas_datareader",
    ]

    deps.extend(list(VERSIONS))
    deps_blob = []

    for modname in deps:
        mod = import_optional_dependency(
            modname, raise_on_missing=False, on_version="ignore"
        )
        ver: Optional[str]
        if mod:
            ver = _get_version(mod)
        else:
            ver = None
        deps_blob.append((modname, ver))

    if as_json:
        j = dict(system=dict(sys_info), dependencies=dict(deps_blob))

        if as_json is True:
            print(j)
        else:
            with codecs.open(as_json, "wb", encoding="utf8") as f:
                json.dump(j, f, indent=2)

    else:
        maxlen = max(len(x) for x in deps)
        tpl = "{{k:<{maxlen}}}: {{stat}}".format(maxlen=maxlen)
        print("\nINSTALLED VERSIONS")
        print("------------------")
        for k, stat in sys_info:
            print(tpl.format(k=k, stat=stat))
        print("")
        for k, stat in deps_blob:
            print(tpl.format(k=k, stat=stat))


def main() -> int:
    from optparse import OptionParser

    parser = OptionParser()
    parser.add_option(
        "-j",
        "--json",
        metavar="FILE",
        nargs=1,
        help="Save output as JSON into file, pass in '-' to output to stdout",
    )

    (options, args) = parser.parse_args()

    if options.json == "-":
        options.json = True

    show_versions(as_json=options.json)

    return 0


if __name__ == "__main__":
    sys.exit(main())
