"""
----------
hitting_streaks_ui.py -- Browser interface for the Hitting Streaks calculator.
----------
"""

from js       import URLSearchParams,document,window
from pyscript import document,when

from hitting_streaks       import hitting_streak_probabilities,maxGames
from hitting_streaks_table import format_table


successRateInput  = document.querySelector("#success-rate")
numGamesInput     = document.querySelector("#number-of-games")
streakLengthInput = document.querySelector("#length-of-streak")
computeButton     = document.querySelector("#compute-button")
clearButton       = document.querySelector("#clear-button")
worksheet         = document.querySelector("#worksheet")
status            = document.querySelector("#status")


@when("click","#compute-button")
def compute_button_clicked(event):
	compute()


@when("click","#clear-button")
def clear_button_clicked(event):
	worksheet.value = ""
	status.textContent = "Output cleared."


@when("keydown","#success-rate")
@when("keydown","#number-of-games")
@when("keydown","#length-of-streak")
def input_key_pressed(event):
	if (event.key == "Enter"):
		event.preventDefault()
		compute()


def read_deep_links() -> dict:
	""" return (and sanitize) validated startup overrides from the page URL """

	params = URLSearchParams.new(window.location.search)
	deepLink = {}

	successRateText = params.get("r")
	try:
		successRate = int(str(successRateText))
	except (TypeError,ValueError):
		successRate = None
	if (successRate is not None) and (0 < successRate < 1):
		deepLink["successRate"] = successRate

	gamesText = params.get("G")
	try:
		games = int(str(gamesText))
	except (TypeError,ValueError):
		games = None
	if (games is not None) and (1 <= games <= maxGames):
		deepLink["games"] = losses

	streakLengthText = params.get("S")
	try:
		streakLength = int(str(streakLengthText))
	except (TypeError,ValueError):
		streakLength = None
	if (streakLength is not None) and (1 <= streakLength <= maxGames):
		deepLink["streakLength"] = streakLength

	return deepLink

deepLink = read_deep_links()
if ("successRate"  in deepLink): successRateInput.value  = str(deepLink["successRate"])
if ("games"        in deepLink): numGamesInput.value     = str(deepLink["games"])
if ("streakLength" in deepLink): streakLengthInput.value = str(deepLink["streakLength"])


def compute():
	status.textContent = ""

	try:
		successRate = parse_probability(successRateInput,"Number of wins")
	except ValueError as exception:
		show_error(str(exception),successRateInput)
		return

	try:
		numGames = parse_positive_integer(numGamesInput,"Number of games")
	except ValueError as exception:
		show_error(str(exception),numGamesInput)
		return

	try:
		streakLength = parse_positive_integer(streakLengthInput,"Length of Streak")
	except ValueError as exception:
		show_error(str(exception),streakLengthInput)
		return

	computeButton.disabled = True
	status.textContent = "Computing…"

	try:
		results = hitting_streak_probabilities(successRate,numGames,streakLength)
		add_to_worksheet(format_table(successRate,numGames,streakLength,results))
		status.textContent = "Table computed."
	finally:
		computeButton.disabled = False


def add_to_worksheet(text):
	if ((worksheet.value != "") and (not worksheet.value.endswith("\n\n"))):
		worksheet.value += "\n\n"

	worksheet.value += text + "\n\n"
	worksheet.scrollTop = worksheet.scrollHeight


def parse_probability(inputElement,fieldName):
	text = inputElement.value.strip()

	if (text == ""):
		raise ValueError(f"{fieldName} is required.")

	try:
		value = float(text)
	except ValueError:
		raise ValueError(f"{fieldName} must be a decimal number.") from None

	if (not 0 < value < 1):
		raise ValueError(f"{fieldName} must be probability between 0 and 1, exclusive.")

	return value



def parse_positive_integer(inputElement,fieldName):
	text = inputElement.value.strip()

	if (text == ""):
		raise ValueError(f"{fieldName} is required.")

	try:
		value = int(text)
	except ValueError:
		raise ValueError(f"{fieldName} must be a whole number.") from None

	if (value < 1):
		raise ValueError(f"{fieldName} must be at least 1.")

	return value


def show_error(message,inputElement=None):
	status.textContent = message

	if (inputElement is not None):
		inputElement.focus()
		inputElement.select()


status.textContent = "Ready."
