#!/usr/bin/env python

# Copyright (c) Microsoft Corporation. All rights reserved.
# Licensed under the MIT license.

import os
import sys
import argparse
from os.path import join as pjoin

import numpy as np

import textworld
import textworld.challenges


def _get_available_challenges():
    challenges = []
    for challenge in textworld.challenges.CHALLENGES:
        challenges.append("tw-{}-level{{N}}".format(challenge))

    return challenges

def exit_listing_challenges(challenge=None):
    msg = ""
    if challenge is not None:
        msg += "Unknown challenge: {}\n\n".format(args.challenge)

    msg += "Available challenges:\n  "
    msg += "\n  ".join(_get_available_challenges())
    msg += "\nwhere {N} is an integer."
    print(msg)
    sys.exit(1)


def parse_args():
    general_parser = argparse.ArgumentParser(add_help=False)

    general_group = general_parser.add_argument_group('General settings')
    general_group.add_argument("--output", default="./tw_games/", metavar="PATH",
                               help="Path where to save the generated game.")
    general_group.add_argument('--seed', type=int)
    general_group.add_argument("--view", action="store_true",
                               help="Display the resulting game.")
    general_group.add_argument("-v", "--verbose", action="store_true")
    general_group.add_argument("-f", "--force", action="store_true")

    cfg_group = general_parser.add_argument_group('Grammar settings')
    cfg_group.add_argument("--theme", default="house",
                           help="Theme to use for generating the text. Default: %(default)s")
    cfg_group.add_argument("--include-adj", action="store_true",
                           help="Turn on adjectives.")
    cfg_group.add_argument("--blend-descriptions", action="store_true",
                           help="Blend descriptions across consecutive sentences.")
    cfg_group.add_argument("--ambiguous-instructions", action="store_true",
                           help="Refer to an object using its type (e.g. red container vs. red chest).")
    cfg_group.add_argument("--only-last-action", action="store_true",
                           help="Intruction only describes the last action of quest.")
    cfg_group.add_argument("--blend-instructions", action="store_true",
                           help="Blend instructions across consecutive actions.")

    parser = argparse.ArgumentParser(parents=[general_parser])
    subparsers = parser.add_subparsers(dest="subcommand", help='Kind of game to make.')

    custom_parser = subparsers.add_parser("custom", parents=[general_parser],
                                          help='Make a custom game.')
    custom_parser.add_argument("--world-size", type=int, default=5, metavar="SIZE",
                               help="Nb. of rooms in the world.")
    custom_parser.add_argument("--nb-objects", type=int, default=10, metavar="NB",
                               help="Nb. of objects in the world.")
    custom_parser.add_argument("--quest-length", type=int, default=5, metavar="LENGTH",
                               help="Minimum nb. of actions the quest requires to be completed.")
    custom_parser.add_argument("--quest-breadth", type=int, default=3, metavar="BREADTH",
                               help="Control how non-linear a quest can be.")

    challenge_parser = subparsers.add_parser("challenge", parents=[general_parser],
                                             help='Generate a game for one of the challenges.')
    challenge_parser.add_argument("challenge",
                                  help="Name of the builtin challenges, e.g. `tw-coin_collector-level210`")

    return parser.parse_args()


if __name__ == "__main__":
    args = parse_args()
    if args.seed is None:
        args.seed = np.random.randint(65635)

    print("Global seed: {}".format(args.seed))

    options = textworld.GameOptions()
    options.seeds = args.seed
    options.force_recompile = args.force
    options.grammar.theme = args.theme
    options.grammar.include_adj = args.include_adj
    options.grammar.only_last_action = args.only_last_action
    options.grammar.blend_instructions = args.blend_instructions
    options.grammar.blend_descriptions = args.blend_descriptions
    options.grammar.ambiguous_instructions = args.ambiguous_instructions

    if args.subcommand == "custom":
        options.nb_rooms = args.world_size
        options.nb_objects = args.nb_objects
        options.quest_length = args.quest_length
        options.quest_breadth = args.quest_breadth
        game_file, game = textworld.make(options, args.output)

    elif args.subcommand == "challenge":
        try:
            # Expected pattern: "tw-challenge-levelN"
            _, challenge, level = args.challenge.split("-")
        except ValueError:
            exit_listing_challenges()

        if challenge not in textworld.challenges.CHALLENGES:
            exit_listing_challenges(args.challenge)

        level = int(level.lstrip("level"))
        make_game = textworld.challenges.CHALLENGES[challenge]
        game = make_game(level, options)
        game_file = textworld.generator.compile_game(game, args.output, force_recompile=args.force)

    print("Game generated: {}".format(game_file))
    if args.verbose:
        print(game.objective)

    if args.view:
        textworld.render.visualize(game, interactive=True)
