#!/usr/bin/env python3

import argparse
import logging
import pathlib
import subprocess
import sys

logger = logging.getLogger('rt-bulk-send')

def parse_arguments(arglist):
    parser = argparse.ArgumentParser()

    action = parser.add_mutually_exclusive_group()
    action.add_argument(
        '--correspond',
        dest='action', action='store_const', const='correspond',
        default='correspond',
        help="Send correspondence on found tickets (default)",
    )
    action.add_argument(
        '--comment',
        dest='action', action='store_const', const='comment',
        help="Comment on found tickets",
    )

    parser.add_argument(
        '--loglevel',
        choices=['debug', 'info', 'warning', 'error', 'critical'],
        default='info',
        help="Show log messages at this level (default %(default)s)",
    )

    parser.add_argument(
        'search',
        help="TicketSQL search, like you would pass to `rt search`",
    )
    parser.add_argument(
        'body_file',
        type=pathlib.Path,
        help="Path to file that has the content of your correspondence/comment",
    )
    parser.add_argument(
        'rt_args', metavar='rt arguments',
        nargs=argparse.REMAINDER,
        help="Additional arguments to pass to `rt correspond/comment`",
    )
    return parser.parse_args(arglist)

def setup_logger(logger, loglevel, stream):
    formatter = logging.Formatter('%(name)s: %(levelname)s: %(message)s')
    handler = logging.StreamHandler(stream)
    handler.setFormatter(formatter)
    logger.addHandler(handler)
    logger.setLevel(loglevel)

def act_on_ticket(ticket_id, args, body_file):
    body_file.seek(0)
    return subprocess.run(
        ['rt', args.action, *args.rt_args, '-m', '-', ticket_id],
        stdin=body_file,
        check=True,
    )

def main(arglist=None, stdout=sys.stdout, stderr=sys.stderr):
    args = parse_arguments(arglist)
    setup_logger(logger, getattr(logging, args.loglevel.upper()), stderr)
    try:
        body_file = args.body_file.open()
    except OSError as error:
        logger.critical("error opening {}: {}".format(args.body_file, error))
        return 3
    if not body_file.seekable():
        logger.critical("file {} must be seekable".format(args.body_file))
        with body_file:
            return 3

    action_verb = args.action.title()
    failures = 0
    with body_file, subprocess.Popen(
            ['rt', 'search', '-i', args.search],
            stdout=subprocess.PIPE,
            universal_newlines=True,
    ) as search_pipe:
        for line in search_pipe.stdout:
            ticket_id = line.rstrip('\n')
            if not ticket_id:
                continue
            logger.info("%sing on %s", action_verb, ticket_id)
            try:
                act_on_ticket(ticket_id, args, body_file)
            except subprocess.CalledProcessError as error:
                logger.error("Failed to %s on %s: rt returned exit code %s",
                             args.action, ticket_id, error.returncode)
                failures += 1

    if search_pipe.returncode != 0:
        logger.critical("`rt search` returned exit code %s", search_pipe.returncode)
        return 4
    elif failures == 0:
        return 0
    else:
        return min(10 + failures, 99)

if __name__ == '__main__':
    exit(main())