"""
----------
slump_streak_ui.py -- Browser interface for the Slump/Streak simulator.
----------
"""

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

from slump_streak_simulator import (simulate_careers,
                                    maxCareerAtBats,maxCareers,maxStreakAtBats)
from slump_streak_table     import format_simulation


careerHitsInput   = document.querySelector("#career-hits")
careerAtBatsInput = document.querySelector("#career-at-bats")
windowHitsInput   = document.querySelector("#window-hits")
windowAtBatsInput = document.querySelector("#window-at-bats")
numCareersInput   = document.querySelector("#number-of-careers")
showDetailsInput  = document.querySelector("#show-details")
simulateButton    = document.querySelector("#simulate-button")
worksheet         = document.querySelector("#worksheet")
status            = document.querySelector("#status")


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


@when("keydown","#career-hits")
@when("keydown","#career-at-bats")
@when("keydown","#window-hits")
@when("keydown","#window-at-bats")
@when("keydown","#number-of-careers")
async def input_key_pressed(event):
	if (event.key == "Enter"):
		event.preventDefault()
		await simulate()


@when("click","#simulate-button")
async def simulate_button_clicked(event):
	await simulate()


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

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

	careerHitsText = params.get("cH")
	try:
		careerHits = int(str(careerHitsText))
	except (TypeError,ValueError):
		careerHits = None
	if (careerHits is not None) and (1 <= careerHits <= maxCareerAtBats):
		deepLink["careerHits"] = careerHits

	careerAtBatsText = params.get("cAB")
	try:
		careerAtBats = int(str(careerAtBatsText))
	except (TypeError,ValueError):
		careerAtBats = None
	if (careerAtBats is not None) and (1 <= careerAtBats <= maxCareerAtBats):
		deepLink["careerAtBats"] = careerAtBats

	numCareersText = params.get("N")
	try:
		numCareers = int(str(numCareersText))
	except (TypeError,ValueError):
		numCareers = None
	if (numCareers is not None) and (1 <= numCareers <= maxCareers):
		deepLink["numCareers"] = numCareers

	windowHitsText = params.get("sH")
	try:
		windowHits = int(str(windowHitsText))
	except (TypeError,ValueError):
		windowHits = None
	if (windowHits is not None) and (1 <= windowHits <= maxStreakAtBats):
		deepLink["windowHits"] = windowHits

	windowAtBatsText = params.get("sAB")
	try:
		windowAtBats = int(str(windowAtBatsText))
	except (TypeError,ValueError):
		windowAtBats = None
	if (windowAtBats is not None) and (1 <= windowAtBats <= maxStreakAtBats):
		deepLink["windowAtBats"] = windowAtBats

	if (params.has("details")):   deepLink["showDetails"] = True

	if   (params.has("slumps")):  deepLink["findStreaks"] = False
	elif (params.has("streaks")): deepLink["findStreaks"] = True

	return deepLink

deepLink = read_deep_links()
if ("careerHits"   in deepLink): careerHitsInput.value    = str(deepLink["careerHits"])
if ("careerAtBats" in deepLink): careerAtBatsInput.value  = str(deepLink["careerAtBats"])
if ("numCareers"   in deepLink): numCareersInput.value    = str(deepLink["numCareers"])
if ("windowHits"   in deepLink): windowHitsInput.value    = str(deepLink["windowHits"])
if ("windowAtBats" in deepLink): windowAtBatsInput.value  = str(deepLink["windowAtBats"])
if ("showDetails"  in deepLink): showDetailsInput.checked = deepLink["showDetails"]
if ("findStreaks" in deepLink):
	if (deepLink["findStreaks"]): document.querySelector("#streak").checked = True
	else:                         document.querySelector("#slump") .checked = True


async def simulate():
	status.textContent = ""

	try:
		careerHits   = parse_integer(careerHitsInput  ,"Career hits")
		careerAtBats = parse_integer(careerAtBatsInput,"Career at bats")
		numCareers   = parse_integer(numCareersInput  ,"Number of careers")
		windowHits   = parse_integer(windowHitsInput  ,"Slump/streak hits")
		windowAtBats = parse_integer(windowAtBatsInput,"Slump/streak at bats")
		findStreaks  = (document.querySelector('input[name="kind"]:checked').value == "streak")
	except ValueError as exception:
		show_error(str(exception))
		return

	simulateButton.disabled = True
	status.textContent = "Simulating…"
	await asyncio.sleep(0.05)  # (give the browser an opportunity to repaint)

	try:
		result = simulate_careers(
			careerHits,careerAtBats,windowHits,windowAtBats,numCareers,
			findStreaks=findStreaks,
			showDetails=showDetailsInput.checked,
			)
		text = format_simulation(careerHits,careerAtBats,windowHits,windowAtBats,result)
		add_to_worksheet(text)
		status.textContent = "Simulation complete."
	except ValueError as exception:
		show_error(str(exception))
	finally:
		simulateButton.disabled = False


def parse_integer(inputElement,fieldName):
	text = inputElement.value.strip()
	if (text == ""):
		inputElement.focus()
		raise ValueError(f"{fieldName} is required.")
	try:
		return int(text)
	except ValueError:
		inputElement.focus()
		raise ValueError(f"{fieldName} must be a whole number.") from None


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 show_error(message):
	status.textContent = message


status.textContent = "Ready."
