#!/usr/bin/env python

__author__ = "Damon May"


import argparse
from jamstats.io.scoreboard_json_io import (
    load_derby_game_from_json_file, load_inprogress_game_from_server)
from jamstats.io import tsv_io
from jamstats.plots.plot_together import save_game_plots_to_pdf
from jamstats.plots import plot_together, jamplots, skaterplots, plot_util
from jamstats.util import resources
from jamstats.data import json_to_pandas, game_data
from jamstats.plots.plot_util import DEFAULT_THEME, VALID_THEMES
from jamstats.util.resources import get_jamstats_version
from jamstats.web import statserver
import logging
import sys
from os.path import exists
from gooey import Gooey, GooeyParser
from attrdict import AttrDict


logger = logging.Logger(__name__)

logging.basicConfig(level=logging.WARNING,
                    format='%(asctime)s | %(name)s |  %(levelname)s: %(message)s')

print(f"jamstats version {get_jamstats_version()}, by Damon May")

@Gooey(program_name="jamstats", program_description="Plot stats from a CRG scoreboard json file or server (v4 or higher)")
def gui_args():
    parser = GooeyParser()
    add_args(parser, True)
    return parser.parse_args()

def cmdline_args():
    parser = argparse.ArgumentParser()
    add_args(parser, False)
    return parser.parse_args()

def add_args(parser, is_gooey):
    # this is necessary because, for some reason, by default Gooy will
    # open a file save dialog rather than a file open dialog
    file_read_kwargs = {"widget": "FileChooser"} if is_gooey else {}
    parser.add_argument('--jsonfile', type=argparse.FileType('r'),
                        help="Scoreboard JSON file to read. If this argument is specified, will read from a file. Either this or scoreboardserver must be specified.",
                        **file_read_kwargs)

    parser.add_argument('--scoreboardserver', type=str,
                        help="server:port to connect to, e.g., localhost:8000. If this argument is specified, will connect to a server. Either this or jsonfile must be specified")
    parser.add_argument('--outfile', type=argparse.FileType('w'),
                        help='File to write. If this argument is specified, will write a PDF or TSV file. '
                        'If ends with ".pdf", write plots to a PDF. If ".tsv" or ".txt" '
                        'write data to tab-separated values file. Either this or jamstatsport must be specified.')
    parser.add_argument('--jamstatsport', type=int,
                        help='Port to serve to, e.g., 8080. If this argument is specified, will serve output to a webserver '
                        'on the specified port. Either this or outfile must be specified unless input is jsonfile.')
    parser.add_argument('--jamstatsip', type=str,
                        help='IP address to serve to, e.g., "192.168.4.21" or "localhost". This argument is optional even if jamstatsport is specified. '
                        'If not specified, will infer your local IP address.')
    parser.add_argument('--anonymize', action="store_true",
                        help="Replace actual skater names with random pregenerated ones?")
    parser.add_argument('--anonymizeteams', action="store_true",
                        help="Replace team names with 'Team 1' and 'Team 2'?")
    parser.add_argument('--debug', action="store_true",
                        help="enable debug logging")
    parser.add_argument('--theme', type=str,
                        default=DEFAULT_THEME,
                        choices=VALID_THEMES,
                        help="Plot theme. This is how you make the plots dark.")
    parser.add_argument('--teamcolor1', type=str,
                        help="Set the color for team 1. Can be of the form 'green' or of the form '#00FF00'")
    parser.add_argument('--teamcolor2', type=str,
                        help="Set the color for team 2. Can be of the form 'green' or of the form '#00FF00'")
    args = parser.parse_args()

    if args.jsonfile is None and args.scoreboardserver is None:
        sys.exit("Must specify either --jsonfile or --scoreboardserver")
    if args.jsonfile is not None and args.scoreboardserver is not None:
        sys.exit("Must specify either --jsonfile or --scoreboardserver, but not both")
    if args.outfile is None and args.jamstatsport is None and args.jsonfile is None:
        sys.exit("Must specify either --outfile or --jamstatsport if connecting to a server")
    if args.outfile is not None and args.jamstatsport is not None:
        sys.exit("Cannot specify both --outfile and --jamstatsport")
    return args

if len(sys.argv) == 1:
    # no args, so run the GUI
    args = gui_args()
elif len(sys.argv) == 2 and sys.argv[1] != "-h" and sys.argv[1] != "--help":
    # one arg, so try to treat it as a json file, and fail if it's not.
    # This option makes it possible to drag-and-drop on Windows.
    if exists(sys.argv[1]):
        args = AttrDict()
        args.jsonfile = open(sys.argv[1])
        args.debug = False
        args.scoreboardserver = None
        args.anonymizeteams = False
        args.anonymize = False
        args.teamcolor1 = None
        args.teamcolor2 = None
        args.jamstatsport = None
        args.outfile = None
        args.theme = None
    else:
        sys.exit(f"File {sys.argv[1]} does not exist")
else:
    args = cmdline_args()

if args.debug:
    stream_handler = logging.StreamHandler()
    stream_handler.setLevel(logging.DEBUG)
    stream_handler.setStream(sys.stdout)

    logger.warning("Enabling debug logging.")
    for mymodule in [plot_together, jamplots, skaterplots, json_to_pandas, game_data,
                     plot_util, resources]:
        mymodule.logger.setLevel(logging.DEBUG)
        mymodule.logger.addHandler(stream_handler)

connect_to_server = False
if args.scoreboardserver:
    try:
        scoreboardserver, scoreboardport = args.scoreboardserver.split(":")
        scoreboardport = int(scoreboardport)
        connect_to_server = True
    except Exception as e:
        print(f"Tried to interpret {args.scoreboardserver} as server:port but failed: {e}")

if connect_to_server:
    derby_game = None
    print(f"Connecting to server {scoreboardserver}, port {scoreboardport}...")
    try:
        derby_game = load_inprogress_game_from_server(scoreboardserver, scoreboardport)
    except Exception as e:
        logger.warn(f"Failed to download in-game data from server {scoreboardserver}:{scoreboardport}: {e}")
else:
    try:
        derby_game = load_derby_game_from_json_file(args.jsonfile.name)
    except Exception as e:
        sys.exit(f"Failed to open file {args.jsonfile.name}: {e}")

if args.anonymizeteams and derby_game is not None:
    print("Anonymizing teams.")
    derby_game.anonymize_team_names()

if args.teamcolor1 is not None and derby_game is not None:
    derby_game.set_team_color_1(args.teamcolor1)
    print(f"Setting team 1 color to {args.teamcolor1}")
if args.teamcolor2 is not None and derby_game is not None:
    derby_game.set_team_color_2(args.teamcolor2)
    print(f"Setting team 2 color to {args.teamcolor2}")

if args.jamstatsport is not None:
    # start a webserver
    statserver.set_game(derby_game)
    kwargs = {
        "anonymize_names": args.anonymize,
        "theme": args.theme,
        "jamstats_ip": args.jamstatsip,
    }
    if connect_to_server:
        kwargs["scoreboard_port"] = scoreboardport
        kwargs["scoreboard_server"] = scoreboardserver
    
    statserver.start(args.jamstatsport, **kwargs)
else:
    # write a file
    if args.outfile is None:
        in_filename = args.jsonfile.name
        if in_filename.lower().endswith(".json"):
            print(f"Output filepath not provided. "
                f"Using input filepath with extension .pdf instead of {in_filename[-5:]}")
            out_filepath = in_filename[:-len(".json")] + ".pdf"
        else:
            sys.exit("Input file doesn't end with .json, so refusing to guess what output file you want."
                "  Please rename your input file or specify an output filepath. Quitting.")
    else:
        args.outfile.close()
        out_filepath = args.outfile.name

    if out_filepath.endswith(".tsv") or out_filepath.endswith(".txt"):
        print("Writing TSV file...")
        tsv_io.write_game_data_tsv(derby_game, out_filepath)
    else:
        print("Writing PDF file...")
        save_game_plots_to_pdf(derby_game, out_filepath, anonymize_names=args.anonymize,
                               theme=args.theme)
    print(f"Wrote {out_filepath}")
