# -*- coding: utf-8 -*-
"""
Here are some function which helps extracting info
online information <GET requests>

"""
from typing import Union, Callable
from typing import List, Tuple 
from typing import Dict
from typing import Any
from .Connection import HTTP
from re import compile, findall
from urllib.parse import unquote
import json, logging
from .Error import (RegexError, VideoInfo, GeoBlockingError, ParsecError)
from .Config import (__issues__,__github__)

logg = logging.getLogger(__name__)

def Get_js(req:HTTP,vid:str) -> Tuple[str, str]:
	'''
	Thie will return the url of base.js
	
	Example..
	>>> Get_Js("M3mJkSqZbX4")
	'https://www.youtube.com/s/player/XXXXXXXXX/player_ias.vflset/en_GB/base.js'
	'''
	data=req._GET(f'https://www.youtube.com/watch?v={vid}').text
	try:
		match=compile(r'<script  src="(.*?)" type="text/javascript" name="player_ias/base" ></script>')
		src=findall(match,data)[0]
	except:
		match=compile(r'jsUrl":"(.*?)"')
		src=findall(match,data)[0]
	if src:
		return "https://www.youtube.com"+src, data
		logg.debug("Successfully got raw js <player_ias/base.js>")
	else:
		logg.error(f"Error raw js <player_ias/base.js> not found <VID:{vid}>")
		raise RegexError(f"base.js not found please report here {__issues__} with {vid}, help us make it more stable for everyone")

def Is_age_restricted(rawhtml:str) -> bool:
	'''
	This will return true or False

	>>> is_age_restricted(htmldata)
	True/False


	'''
	if "og:restrictions:age" in rawhtml:
		return True
	return False

def Get_video_info(req:HTTP,url:str) -> Tuple[Any, bool, Dict[str, str]]:
	'''
	This willl return video info 
	from: https://youtube.com/get_video_info

	:args str url
		url in string <get_video_info>

	:rtype: Tuple[Any, bool, Dict[str, str]]
	:returns: the extracted data, true if signature found, raw data dict
	'''
	try:
		r=req._GET(url).text
		Fdata = {unquote(o.split("=")[0]):unquote(o.split("=")[1]) for o in r.split("&")}
		data = json.loads(Fdata["player_response"])
		r = data = json.loads(Fdata["player_response"]) # to return this  
		assert CheckPlayable(data["playabilityStatus"]) == True, f'Video is {data["playabilityStatus"]["status"]}, Please use Proxy/VPN to bypass Geo-blocking'
		data = GetStreamingData(data["streamingData"])
		# data = data["streamingData"]["adaptiveFormats"] + data["streamingData"]["formats"]
		issig:bool = Videodata_parse(data)
		logg.debug(f"We Successfully received video data/info")
		return data, issig, r
	except:
		logg.error(f"Video Info not found <{url}> please contact <{__issues__}>")
		raise VideoInfo(f"Video Info not found <{url}> please contact <{__issues__}>, help us make it more stable for everyone")
def Videodata_parse(data:Dict[Any, Any]) -> bool:
	'''
	Takes Data and parsec the signatureCipher
	and upadte the url and del the signatureCipher
	if it has or return the same
	'''
	logg.debug(f"Videodata processing ..... ")
	sig:bool=False
	for n in data:
		if "signatureCipher" in n.keys():
			sig=True
			url = _parsesignatureCipher(n["signatureCipher"])
			del n["signatureCipher"]
			n.update(url)
		else:
			sig=False
			continue
	logg.debug(f"Videodata processing Completed, Signature found: <{sig}> ")
	return sig

def _parsesignatureCipher(signatureCipherraw:str) -> Dict[Any, Any]:
	'''
	this will convert the str of signatureCipher
	to dict and return
	'''
	data={unquote(o.split("=")[0]):unquote(o.split("=")[1]) for o in signatureCipherraw.split("&")}
	return data


def Req_get(req:HTTP,url:str) -> str:
	'''
	Send simple get request with object
	'''
	return req._GET(url).text

def CheckPlayable(data:Dict[Any, Any]) -> bool:
	'''
	Here we will check is video is really
	playable or not/ Check if video is aviable
	for you or in your country.
	'''
	if data["status"] !="OK":
		logg.info(f'Video is {data["status"]}')
		raise GeoBlockingError(f'Video is {data["status"]}, {data["errorScreen"]["playerErrorMessageRenderer"]["subreason"]["runs"][0]["text"].replace("+"," ")}')
		return False
	return True


def GetStreamingData(data:Dict[Any, Any]) -> List[Any]:
	'''
	This will return all the streams with or without audio streams, ``adaptiveFormats`` and ``formats``.
	'''
	d=[]

	for n in data["formats"]:
		mtype, vcode=n["mimeType"].split(";+")
		n["mimeType"] = mtype
		mtype, forma = mtype.split("/")
		key, value = vcode.split("=")
		n["type"] = "both"
		n["format"] = forma
		n[key] = value.replace('"',"")
		d.append(n)

	for n in data["adaptiveFormats"]:
		mtype, vcode=n["mimeType"].split(";+")
		n["mimeType"] = mtype
		mtype, forma = mtype.split("/")
		key, value = vcode.split("=")
		n["type"] = mtype
		n["format"] = forma
		n[key] = value.replace('"',"")
		d.append(n)

	return d


def Get_playlist_videos(http:HTTP, url:str) -> Dict[str,str]:
	'''
	This will parse the initial json dict from web page source.

	:param HTTP http:
		 Pass the :class:`HTTP <HTTP>` object.
	:param str url:
		pass the plsylist url

	:rtype: Dict[str,str]
	:returns: The dict of of video details 
	'''
	html = http._GET(url).text.replace("\n","")
	f = ""
	try:
		match = compile(r'window\["ytInitialData"\] = (.*?);')
		f = findall(match, html)[0]
	except:
		match = compile(r'var ytInitialData = (.*?);')
		f = findall(match, html)[0]


	if f:
		return json.loads(f)
	else:
		logg.debug(f'RegexError we cannot found {match}')
		raise RegexError(f'RegexError we cannot found {match}')
	

def Continuation(http:HTTP,videos:List[Dict[str,str]], token:str) -> str:
	'''
	This will extract the data we will get from **browse_ajax** API.

	:param HTTP http:
		Pass the :class:`HTTP <HTTP>` object.
	:param List[Dict[str,str]] videos:
		Pass the videos dicts list.
	:param str token:
		Pass the token if any.

	:rtype: str
	:returns: The new/next continuous token if available.
	'''
	params = {
		"ctoken": token
	}
	headers={
		'X-YouTube-Client-Name': '1',
		'X-YouTube-Client-Version': '2.20200720.00.02'
	}
	token = ""
	data = http._GET("https://www.youtube.com/browse_ajax",params=params,headers=headers).json()[-1]
	for n in data["response"]["onResponseReceivedActions"][0]["appendContinuationItemsAction"]["continuationItems"]:
		if "playlistVideoRenderer" in n.keys():
			tmp = dict()
			tmp["vid"] = n["playlistVideoRenderer"]["videoId"]
			tmp["name"] = n["playlistVideoRenderer"]["title"]["runs"][0]["text"]
			videos.append(tmp)
		elif "continuationItemRenderer" in n.keys():
			token = n["continuationItemRenderer"]["continuationEndpoint"]["continuationCommand"]["token"]
		else:
			raise ParsecError(f'Serious Bug please report here {__issues__}')

	return token

def Parse_search_json(data:Dict[str,str], videos:List[Dict[str,str]]) -> bool:
	# print(json.dumps(data))
	for n in data["contents"]["twoColumnSearchResultsRenderer"]["primaryContents"]["sectionListRenderer"]["contents"][0]["itemSectionRenderer"]["contents"]:
		try:
			det = n["videoRenderer"]
			videos.append(dict(vid=det["videoId"],name=det["title"]["runs"][0]["text"]))
		except:
			continue
	return True



def Search_results(http:HTTP, query:str, videos:List[Dict[str,str]],country:str) -> bool:
	'''
	This will parse the initial json dict from web page source.
	
	:param HTTP http:
		Pass the :class:`HTTP <HTTP>` object.
	:param str query:
		pass query for searching.
	:param str videos:
		pass the video list of dicts
	:param str country:
		pass the country code

	:rtype: bool
	:returns: true or false depend on search results.

	'''
	SEARCH_URL = "https://www.youtube.com/results"
	PARAMS = {
		"search_query":query,
		"gl":country.upper()
	}
	HEADERS = {}

	html = http._GET(SEARCH_URL, params=PARAMS,headers=HEADERS).text.replace("\n","")
	try:
		match = compile(r'var ytInitialData = (.*?);')
		f = findall(match, html)[0]
		f = json.loads(f)
	except:
		logg.debug(f'RegexError we cannot found {match}')
		raise RegexError(f'RegexError we cannot found {match}')

	if f:
		if Parse_search_json(f,videos):
			return True
		else:
			return False
