#!/usr/bin/env python3

# Copyright (c) 2009 Giampaolo Rodola'. All rights reserved.
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.

"""
Print PYPI statistics in MarkDown format.
Useful sites:
* https://pepy.tech/project/psutil
* https://pypistats.org/packages/psutil
* https://hugovk.github.io/top-pypi-packages/
"""

from __future__ import print_function

import json
import os
import subprocess
import sys

import pypinfo  # NOQA

from psutil._common import memoize


AUTH_FILE = os.path.expanduser("~/.pypinfo.json")
PKGNAME = 'psutil'
DAYS = 30
LIMIT = 100
GITHUB_SCRIPT_URL = "https://github.com/giampaolo/psutil/blob/master/" \
                    "scripts/internal/pypistats.py"
LAST_UPDATE = None
bytes_billed = 0


# --- get

@memoize
def sh(cmd):
    assert os.path.exists(AUTH_FILE)
    env = os.environ.copy()
    env['GOOGLE_APPLICATION_CREDENTIALS'] = AUTH_FILE
    p = subprocess.Popen(cmd, shell=True, stdout=subprocess.PIPE,
                         stderr=subprocess.PIPE, universal_newlines=True)
    stdout, stderr = p.communicate()
    if p.returncode != 0:
        raise RuntimeError(stderr)
    assert not stderr, stderr
    return stdout.strip()


@memoize
def query(cmd):
    global bytes_billed
    ret = json.loads(sh(cmd))
    bytes_billed += ret['query']['bytes_billed']
    return ret


def top_packages():
    global LAST_UPDATE
    ret = query("pypinfo --all --json --days %s --limit %s '' project" % (
        DAYS, LIMIT))
    LAST_UPDATE = ret['last_update']
    return [(x['project'], x['download_count']) for x in ret['rows']]


def ranking():
    data = top_packages()
    i = 1
    for name, downloads in data:
        if name == PKGNAME:
            return i
        i += 1
    raise ValueError("can't find %s" % PKGNAME)


def downloads():
    data = top_packages()
    for name, downloads in data:
        if name == PKGNAME:
            return downloads
    raise ValueError("can't find %s" % PKGNAME)


def downloads_pyver():
    return query("pypinfo --json --days %s %s pyversion" % (DAYS, PKGNAME))


def downloads_by_country():
    return query("pypinfo --json --days %s %s country" % (DAYS, PKGNAME))


def downloads_by_system():
    return query("pypinfo --json --days %s %s system" % (DAYS, PKGNAME))


def downloads_by_distro():
    return query("pypinfo --json --days %s %s distro" % (DAYS, PKGNAME))


# --- print


templ = "| %-30s | %15s |"


def print_row(left, right):
    if isinstance(right, int):
        right = '{0:,}'.format(right)
    print(templ % (left, right))


def print_header(left, right="Downloads"):
    print_row(left, right)
    s = templ % ("-" * 30, "-" * 15)
    print("|:" + s[2:-2] + ":|")


def print_markdown_table(title, left, rows):
    pleft = left.replace('_', ' ').capitalize()
    print("### " + title)
    print()
    print_header(pleft)
    for row in rows:
        lval = row[left]
        print_row(lval, row['download_count'])
    print()


def main():
    downs = downloads()

    print("# Download stats")
    print("")
    s = "psutil download statistics of the last %s days (last update " % DAYS
    s += "*%s*).\n" % LAST_UPDATE
    s += "Generated via [pypistats.py](%s) script.\n" % GITHUB_SCRIPT_URL
    print(s)

    data = [
        {'what': 'Per month', 'download_count': downs},
        {'what': 'Per day', 'download_count': int(downs / 30)},
        {'what': 'PYPI ranking', 'download_count': ranking()}
    ]
    print_markdown_table('Overview', 'what', data)
    print_markdown_table('Operating systems', 'system_name',
                         downloads_by_system()['rows'])
    print_markdown_table('Distros', 'distro_name',
                         downloads_by_distro()['rows'])
    print_markdown_table('Python versions', 'python_version',
                         downloads_pyver()['rows'])
    print_markdown_table('Countries', 'country',
                         downloads_by_country()['rows'])


if __name__ == '__main__':
    try:
        main()
    finally:
        print("bytes billed: %s" % bytes_billed, file=sys.stderr)
