#!/usr/bin/env python
from __future__ import absolute_import
import os.path
import glob
import argparse
import logging
import tempfile
from itertools import dropwhile, takewhile
from functools import partial
from subprocess import check_call as _check_call
try:
    from subprocess import check_ouput as _check_ouput
except ImportError:
    import subprocess

    def _check_output(*args, **kwargs):
        process = subprocess.Popen(stdout=subprocess.PIPE, *args, **kwargs)
        output, _ = process.communicate()
        retcode = process.poll()
        if retcode:
            error = subprocess.CalledProcessError(retcode, args[0])
            error.output = output
            raise error
        return output


check_call = partial(_check_call, shell=True)
check_output = partial(_check_output, shell=True)

# Constants
DEFAULT_REQUIREMENTS_FILE = 'requirements.txt'
GLOB_PATTERN = '*requirements.txt'
PIP_IGNORE_FILE = '.pipignore'
SPLIT_PATTERN = '## The following requirements were added by pip --freeze:'


def setup_logging(verbose):
    if verbose:
        level = logging.DEBUG
    else:
        level = logging.INFO

    logging.basicConfig(level=level, format='%(message)s')


def parse_args():
    parser = argparse.ArgumentParser(
            description='Rewrites requirements.txt to match your virtualenv.')
    parser.add_argument('--verbose', '-v', action='store_true', default=False,
            help='Show more output')
    parser.add_argument('files', nargs='*')
    return parser.parse_args()


def pip_partition(lines):
    no_split_match = lambda line: line != SPLIT_PATTERN
    split_match = lambda line: line == SPLIT_PATTERN
    first = takewhile(no_split_match, lines)
    second = dropwhile(split_match, dropwhile(no_split_match, lines))
    return (list(first), list(second))


def pip_info(filename):
    cmd = 'pip freeze -lr %s' % (filename,)
    raw = check_output(cmd)
    lines = raw.split('\n')
    p = pip_partition(lines)
    return p


def append_lines(lines, filename):
    with open(filename, 'a') as f:
        for line in lines:
            f.write('%s\n' % line)


def rewrite(filename, lines):
    with open(filename, 'w') as f:
        for line in sorted(lines, key=str.lower):
            line = line.strip()
            if line:
                f.write('%s\n' % line)


def dump_requirements(files):
    _, tmpfile = tempfile.mkstemp()
    check_call('cat %s | sort -fu > %s' % (' '.join(files), tmpfile))
    _, new = pip_info(tmpfile)
    check_call('rm %s' % tmpfile)
    append_lines(new, files[0])

    for filename in files:
        if os.path.basename(filename) == PIP_IGNORE_FILE:  # never rewrite the pip ignore file
            continue
        pkgs, _ = pip_info(filename)
        rewrite(filename, pkgs)


def find_default_files():
    req_files = glob.glob(GLOB_PATTERN)
    try:
        req_files.remove(DEFAULT_REQUIREMENTS_FILE)
    except ValueError:
        pass

    files = [DEFAULT_REQUIREMENTS_FILE]
    files += req_files
    if os.path.exists(PIP_IGNORE_FILE):
        files.append(PIP_IGNORE_FILE)
    return files


def main():
    args = parse_args()
    setup_logging(args.verbose)

    if not args.files:
        args.files = find_default_files()
    dump_requirements(args.files)


if __name__ == '__main__':
    main()
