#!/usr/bin/env python3
__version__ = "1.0.0"
# YOU MUST INCLUDE THE SLASH AT THE END
WEBSITE = "https://gfl.amaryllisworks.pw/"
#WEBSITE = "http://127.0.0.1:8000/"

# imports
from typing import BinaryIO, List, Any, Dict, Set, Tuple, TypedDict, Callable, ContextManager
from typing_extensions import Literal, Union
from collections.abc import Generator
from contextlib import contextmanager, suppress

#import urllib.request
import re
import argparse
import sys
import requests
import json
import io
import os
from pathlib import Path
import inquirer
from http.server import HTTPServer, SimpleHTTPRequestHandler
from concurrent.futures import ThreadPoolExecutor

# Helper functions from gfLib...

class bcolors:
	HEADER = '\033[95m'
	OKBLUE = '\033[94m'
	OKGREEN = '\033[92m'
	WARNING = '\033[93m'
	FAIL = '\033[91m'
	ENDC = '\033[0m'
	BOLD = '\033[1m'
	UNDERLINE = '\033[4m'
    
def printWarn(text):
	print(bcolors.WARNING + text + bcolors.ENDC)
	
def printError(text):
	print(bcolors.FAIL + text + bcolors.ENDC)
	
def printOK(text):
	print(bcolors.OKGREEN + text + bcolors.ENDC)


import importlib.util
if importlib.util.find_spec("inquirer") is None:
	print(bcolors.FAIL + "Hey moron, you didn't install the dependencies.")
	print("Run pip install -r requirements.txt and try again."+bcolors.ENDC)
	sys.exit(1)

def host_http_server(port:int=8000):
	os.chdir("data")
	server = HTTPServer(("0.0.0.0", port), SimpleHTTPRequestHandler)
	print(f"Navigate to http://localhost:{port} in your web browser to access the interpreter.")
	server.serve_forever()

def download_file(url, destination):
	resp:requests.Response  = requests.get(url, allow_redirects=True)
	resp.raise_for_status()
	
	dest_path = Path(destination).parent
	os.makedirs(dest_path, exist_ok=True)
	with open(destination,'wb') as outFile:
		outFile.write(resp.content)
		

# Main program goes here
if __name__ == "__main__":
	from rich import print
	from rich.layout import Layout, LayoutRender
	from rich.progress import track, Progress
	from rich.live import Live
	from rich.text import Text
	from rich.console import Console
	from rich.panel import Panel
	#from downloader import download
	from time import sleep

	parser = argparse.ArgumentParser(description="Download GFL interpreter website")
	#parser.add_argument("host",action='store_true',help="Host the web server. If used in conjunction with --update, will host after updating.")
	#parser.add_argument("update",action='store_true',help="Update the site files.")
	parser.add_argument("--port",type=int,help="Port to use for hosting, from 1024 to 65535.", default=8000)
	parser.add_argument(
		"mode",
		nargs="?",
		choices=["run", "update"],
		#default=None,
		help="Whether to run the interpreter or update it. If not specified it will ask."
	)

	args = parser.parse_args()

	if not args.mode:
		if os.path.exists(os.path.join("data","index.html")):
			choice = inquirer.list_input(
				"What would you like to do?",
				choices=["Update the interpreter's files","Use the interpreter"]
			)
			if choice is None:
				sys.exit(-1)
			elif choice == "Use the interpreter":
				args.mode = "run"
			else:
				args.mode = "update"
		else: #If no file exists, then we can't run it. So default to update
			args.mode = "update"

	if args.mode == "run":
		host_http_server(args.port)
	else:
		os.makedirs("data", exist_ok=True)

		#Always download these files
		files = [
			"index.html",
			"stylesheet.css",
			"script.js",
			"client-side-translator.js",
			"portraitInformation.json",
			"chapterDatabase.json",
		]
		for f in files:
			download_file(WEBSITE+f,os.path.join("data",f))
			print("Downloaded "+f)

		with open(os.path.join("data","index.html"), 'r', encoding='utf-8') as f:
			data = f.read()
			data = data.replace("https://cdnjs.cloudflare.com/ajax/libs/materialize/1.0.0/css/materialize.min.css","materialize.min.css")
			data = data.replace("https://cdnjs.cloudflare.com/ajax/libs/materialize/1.0.0/js/materialize.min.js","materialize.min.js")

		with open(os.path.join("data","index.html"), 'w', encoding='utf-8') as f_out:
			f_out.write(data)

		m_css = os.path.join("data","materialize.min.css")
		if not os.path.exists(m_css):
			download_file("https://cdnjs.cloudflare.com/ajax/libs/materialize/1.0.0/css/materialize.min.css",m_css)
			print("Downloaded "+m_css)
		m_js = os.path.join("data","materialize.min.js")
		if not os.path.exists(m_js):
			download_file("https://cdnjs.cloudflare.com/ajax/libs/materialize/1.0.0/js/materialize.min.js", m_js)
			print("Downloaded "+m_js)

		with open(os.path.join("data","chapterDatabase.json"), encoding="utf-8") as f:
			DATABASE = json.load(f)
			#MUSIC:Dict[str,str] = DATABASE['music']
			MUSIC:Set[str] = set([f+".ogg" for f in DATABASE['music'].values()])
			SFX:Set[str] = set([f+".ogg" for f in DATABASE['se'].values()])
			AVGTEXTURE:Set[str] = set([f+".png" for f in DATABASE['bg']])
			VIDEOS = [ '2021Winter.mp4', '2023SpringEd_2.mp4', '202404ActivityPV.mp4', '202406ActivityPV.mp4', '202407ActivityPV.mp4', '202408ActivityPV.mp4', '202410ActivityPV.mp4', 'AllSeeingEye01.mp4', 'AllSeeingEye02.mp4', 'AllSeeingEye03.mp4', 'AllSeeingEye04.mp4', 'DoomsdayClock01.mp4', 'DoomsdayClock02.mp4', 'DoomsdayClock03.mp4', 'DoomsdayClock04.mp4', 'DoomsdayClock05.mp4', 'DoomsdayClock06.mp4', 'DoomsdayClock07.mp4' ]

			with open(os.path.join("data","portraitInformation.json"), encoding="utf-8") as ff:
				tmp:Dict[str,List[str]] = json.load(ff)
				AVGPIC:List[str] = []
				for v in tmp.values():
					for f in v:
						if f: #Skip empty entries
							AVGPIC.append(f+".png")
					#AVGPIC.extend([f+".png" for f in v])
					#AVGPIC.extend(v)

		FOLDERS = {
			"assets":[ 'favicon-16x16.png', 'favicon-32x32.png', 'favicon.ico', 'maskBox2.png', 'maskBox.png', 'snow1.png', 'snow2.png', 'snow3.png' ],
			'audio':MUSIC,
			"avgtexture":AVGTEXTURE,
			"pic":AVGPIC,
			"sfx":SFX,
			'video':VIDEOS,
			#"avgtxt":[]
		}
		#print(promptResult['Language'])
		#sys.exit(0)

		# for count in track(FOLDERS):
		# 	#print(count)
		# 	for letter in track("ABCDEF", transient=True):
		# 		print(f"Stage {count}{letter}")
		# 		sleep(0.1)

		# 	sleep(0.1)

		layout = Layout()
		layout.split_column(
			Layout(name="upper"),
			Layout(name="lower"),
			Layout(name="total"),
		)
		#print(layout)

		#logger = Text()
		log = []

		tasks_progress = Progress()
		tasks = [
			tasks_progress.add_task("Download main site files...", total=len(FOLDERS['assets'])),
			tasks_progress.add_task("Download music...", total=len(MUSIC)),
			tasks_progress.add_task("Download backgrounds...", total=len(AVGTEXTURE)),
			tasks_progress.add_task("Download character images...", total=len(AVGPIC)),
			tasks_progress.add_task("Download sound effects...", total=len(SFX)),
			tasks_progress.add_task("Download videos...", total=len(VIDEOS)),
		]


		promptResult = inquirer.prompt([
			inquirer.Checkbox(
				"Language",
				message="What languages to download? (Select at least one. Use space to select)",
				choices=[
					("English","en"),
					("Chinese","ch"),
					("Japanese","jp"),
					("Korean","kr"),
					("Russian (Fan Translation)","ru")
				],
				default=['en','ch']
			)
		])
		if promptResult is None or promptResult['Language'] is None:
			sys.exit(1)
		for avgtxt_lang in promptResult['Language']:
			os.makedirs(os.path.join("data","avgtxt",avgtxt_lang), exist_ok=True)

			all_files = []
			js = DATABASE['story']
			for t in js: #main, side, etc
				for i in range(len(js[t])):
					for j in range(len(js[t][i]['episodes'])):
						ep = js[t][i]['episodes'][j]
						for part in ep['parts']:
							all_files.append(part)
							#FOLDERS['avgtxt'].append('')
			k = os.path.join("avgtxt",avgtxt_lang)
			FOLDERS[k] = all_files
			tasks.append(tasks_progress.add_task("Download text for language "+avgtxt_lang, total=len(all_files)))

		layout['lower'].size = len(tasks)+2
		layout['total'].size = 3


		total_progress = Progress()
		total_task = total_progress.add_task(f"Folder 1/{len(tasks)+1}: ", total=len(tasks))

		#total_progress.start()
		#tasks_progress.start()

		# layout = Layout()
		# layout.split_column(
		# 	Layout(name="upper"),
		# 	Layout(tasks_progress, name="lower"),
		# 	Layout(total_progress, name="total"),
		# )
		# layout['lower'].size = 10
		# layout['total'].size = 3

		def multithreaded_download_and_update(task, server_url, download_path):

			upper_region:LayoutRender = next(iter(layout.map.values()))
			height = upper_region.region.height - 2

			visible = "\n".join(log[-height:])

			#log.append(server_url)
			#screen.refresh()
			#log.append("Downloading "+download_path)
			#layout['upper'].update(Panel(visible, title="Console Log"))
			#screen.refresh()

			if os.path.exists(download_path):
				log.append("Skipped "+download_path+" because file already exists")
			else:
				try: 
					download_file(server_url, download_path)
					log.append("[green]Downloaded "+download_path+"[/]")
				except:
					log.append("[red]Error downloading "+server_url+"[/]")
					print("[red]Error downloading "+server_url+"[/]")
			#log.append("Downloaded "+download_path)
			tasks_progress.advance(task)


			layout['upper'].update(Panel(visible, title="Console Log"))
			layout['lower'].update(Panel(tasks_progress, title="Current Progress"))
			screen.refresh()


		cur_task = 0
		with Live(layout, auto_refresh=False) as screen:
			layout['total'].update(Panel(total_progress,title="Total Progress"))

			for folder_path, files_in_folder in FOLDERS.items():


				with ThreadPoolExecutor(max_workers=5) as pool:
					for file in files_in_folder:
						if not file:
							tasks_progress.advance(tasks[cur_task])
							continue

						server_url = f"{WEBSITE}{folder_path}/{file}"
						download_path = os.path.join("data",folder_path, file)
						pool.submit(multithreaded_download_and_update, tasks[cur_task], server_url, download_path)
				cur_task +=1
				total_progress.advance(total_task)
				total_progress.update(task_id=total_task, description=f"Folder {cur_task+1}/{len(tasks)+1}: ")

			#with ThreadPoolExecutor(max_workers=5) as pool:
			#	for song in MUSIC:



				# download_file(server_url, download_path)

				# #tasks_progress.console.print(image)
				# #tasks_progress.update(task_id=task, description="Downloading "+image)

				# #log.append(layout["upper"].size)
				# upper_region:LayoutRender = next(iter(layout.map.values()))
				# height = upper_region.region.height - 2


				# visible = "\n".join(log[-height:])
				# log.append("Downloaded "+download_path)

				# tasks_progress.advance(task1)
				# layout['upper'].update(Panel(visible, title="Console Log"))
				# layout['lower'].update(Panel(tasks_progress, title="Current Progress"))
				# screen.refresh()
				#sleep(0.1)

				#print()
				#sys.exit(0)


			# task1 = progress.add_task("[red]Total Progress...", total=1000)
			# task2 = progress.add_task("[green]Processing...", total=1000)
			# task3 = progress.add_task("[cyan]Cooking...", total=1000)

			# while not progress.finished:
			# 	progress.update(task1, advance=0.5)
			# 	progress.update(task2, advance=0.3)
			# 	progress.update(task3, advance=0.9)
			# 	sleep(0.02)


# questions = [
#     inquirer.Checkbox(
#         "interests",
#         message="What are you interested in?",
#         choices=["Computers", "Books", "Science", "Nature", "Fantasy", "History"],
#         default=["Computers", "Books"],
#     ),
# ]