import re
import json

from datetime     import datetime, timedelta
from ..core.tools import log
from .analyzer    import Analyzer
from ..downloader.youtube import (
	download_xml,
	download_html,
)
from ..core.sock  import (
	download_https
)
from ..core.download  import Download




class Youtube_Analyzer(Analyzer):
	SITE='[youtube]'
	URL_MATCH=r'(?:https://|)(?:www\.|m.|)youtube\.com/(?P<type>c/|channel/|user/|playlist\?list=|@)(?P<ID>[a-zA-Z0-9_-]*)'
	RE_CHANNEL=r'UC[A-Za-z0-9_-]{22}$'
	RE_PLAYLIST=r'PL[A-Za-z0-9_-]{32}$'
	TEST=[
		'https://www.youtube.com/channel/UCyg3MF1KU3dUK0HJBBoRYOw',
		'https://www.youtube.com/playlist?list=PL0H7ONNEUnnt59niYAZ07dFTi99u2L2n_',
		'https://www.youtube.com/channel/UCDlLfadiQHJuFkJnSBBnQsQ',
		'https://m.youtube.com/channel/UCDlLfadiQHJuFkJnSBBnQsQ',
		'https://www.youtube.com/c/RapidsCrew',
		'https://www.youtube.com/c/RestezChezVous',
		'UCyg3MF1KU3dUK0HJBBoRYOw',
		'PL0H7ONNEUnnt59niYAZ07dFTi99u2L2n_',
		'UCDlLfadiQHJuFkJnSBBnQsQ',
	]

	def __init__(self, url_id=''):
		self.id = self.extract_id(url_id)
		self.type = self._type_id(self.id)  # True --> chanel False -- > Playlist
		self.content = None

	def extract_id(self, url):
		if url == '':
			return ''
		match = self.match(url)
		if not match:
			return url
		if not re.match(self.RE_CHANNEL, match.group('ID')) and not re.match(self.RE_PLAYLIST, match.group('ID')):
			site = Download(True, 'www.youtube.com')
			path = re.findall('youtube.com(/.*)$', url)[0]
			site.download(path, headers={'Cookie': 'SOCS=CAESNQgDEitib3FfaWRlbnRpdHlmcm9udGVuZHVpc2VydmVyXzIwMjMwOTI2LjA1X3AwGgJmciACGgYIgITTqAY', 'Referer': 'https://consent.youtube.com/'})
			if site.status == '303' and 'Location' in site.headers:
				nurl = re.findall(r'Location: (.*)', site.headers)[0]
				path = re.findall('youtube.com(/.*)$', nurl)[0]
				site.download(path, headers={'Cookie': 'SOCS=CAESNQgDEitib3FfaWRlbnRpdHlmcm9udGVuZHVpc2VydmVyXzIwMjMwOTI2LjA1X3AwGgJmciACGgYIgITTqAY', 'Referer': 'https://consent.youtube.com/'})
			ids = re.findall(r'(UC[A-Za-z0-9_-]{22})', site.body)
			dup_uids = {}
			for uid in ids:
				if uid not in dup_uids:
					dup_uids[uid] = 1
				else:
					dup_uids[uid] += 1
			return max(dup_uids, key=dup_uids.get, default='')
		return match.group('ID')

	def add_sub(self, url):
		sub = self.extract_id(url)
		tid = self._type_id(sub)
		data = download_xml(sub, type_id=tid, split=False)
		if data is None:
			log.Error("The channel/playlist can't be add. It could be delete.")
			return None
		match = re.findall(r'<(?:title|name)>(.+?)</(?:title|name)>', data)
		if match != []:
			return sub + '\t' + match[0]
		log.Warning("The channel/playlist can't be add. It could be delete.")
		return None

	def real_analyzer(self):
		"""Recover all the videos of a channel or a playlist
		and add the informations in $HOME/.cache/youtube_sm/data/."""
		if self.method == '0':
			linfo = download_xml(self.id, self.type)
		elif self.method == '1':
			linfo = download_html(self.id, self.type)
		if linfo is None:
			return
		info = self.info_rss
		if self.method == '1':
			info = self.info_html
			if self.type:  # Channel
				linfo = linfo["contents"]["twoColumnBrowseResultsRenderer"]["tabs"][1]["tabRenderer"]["content"]["sectionListRenderer"]["contents"][0]["itemSectionRenderer"]["contents"][0]["gridRenderer"]["items"]
		for i in linfo:
			self.content = None
			info(i)
			if self.content is not None:
				self.write()

	def _full_url(self):
		if self.type:
			return 'https://www.youtube.com/channel/' + self.id
		return 'https://www.youtube.com/playlist?list=' + self.id

	def info_html(self, i):
		"""Recover the informations of the html page"""
		if self.type:  # Channel
			if "gridVideoRenderer" not in i:
				return 
			i = i["gridVideoRenderer"]
			self.content = {
				'url': i["videoId"],
				'title': i["title"]["runs"][0]["text"],
				'date': self.date_convert(i["publishedTimeText"]["simpleText"].replace('Streamed', '')),
				'uploader': re.findall('.* by (.+?) \d* \w* ago.*', i["title"]["accessibility"]["accessibilityData"]["label"])[0],
				# 'view': i["viewCountText"]["simpleText"],
			}
		else:  # Playlist
			self.content = self.info(i, {
				'url': {'re':r'data-video-id="(.{11})"'},
				'title': {'re':r'data-video-title="(.+?)"'},
				'uploader': {'re':r'data-video-username="(.+?)"'},
				'date': {'default': datetime.now()},
			})

	def info_rss(self, i):
		"""Recover the informations of a rss page"""
		self.content = self.info(i, {
			'url':         {'re': r'<yt:videoId>(.{11})</yt:videoId>'},
			'title':       {'re': r'<media:title>(.*)</media:title>'},
			'uploader':    {'re': r'<name>(.*)</name>'},
			'date':        {'re': r'<published>(.*)\+', 'date': '%Y-%m-%dT%H:%M:%S'},
			'view':        {'re': r'views="(.+?)"'},
		})
		if self.content is not None:
			self.content['view'] = self.content['view'].replace(',', '')

	def write(self):
		"""Write the information in a file"""
		self.content['image'] = 'https://i.ytimg.com/vi/{}/mqdefault.jpg'.format(self.content['url'])
		self.content['url'] = 'https://www.youtube.com/watch?v=' + self.content['url']
		self.content['url_uploader'] = self._full_url()
		self.file.add(**self.content)

	def _type_id(self, id):
		"""True = Channel; False = Playlist"""
		if re.match(self.RE_CHANNEL, id):
			return True
		elif re.match(self.RE_PLAYLIST, id):
			return False
		else:
			return True

	def date_convert(self, date):
		"""
		Convert "2 day ago" -> datetime format
		"""
		value, unit, _ = date.split()
		if unit in ['month', 'months']:
			unit = 'days'
			value = int(value) * 31
		elif unit in ['year', 'years']:
			unit = 'days'
			value = int(value) * 365
		elif unit in ['minute', 'hour', 'day', 'week']:
			unit += 's'
		delta = timedelta(**{unit: int(value)})
		date = datetime.now() - delta
		return date

	def old(self, sub, since):
		sub = self.extract_id(sub)
		data = download_xml(sub, self._type_id(sub))
		if data is None:
			self.subis(sub, self.ISDEAD)
		elif data == []:
			self.subis(sub, self.ISEMPTY)
		else:
			content = self.info(data[0], {
				'date': {'re': '<published>(.*)\+', 'date':'%Y-%m-%dT%H:%M:%S'},
				'name': {'re': '<name>(.+?)</name>'},
			})
			if content is None:
				log.Error('Fail to parse the rss feed')
			else:
				if since > content['date']:
					self.subis(content['name'], content['date'])
				else:
					self.subis(content['name'], self.ISOK)

	def dead(self, sub):
		""" Print the dead channel """
		sub = self.extract_id(sub)
		linfo = download_xml(sub, self._type_id(sub))
		if linfo is None:
			self.subis(sub, self.ISDEAD)
		elif linfo is []:
			self.subis(sub, self.ISEMPTY)
		else:
			self.subis(sub, self.ISOK)
