import requests
from bs4 import BeautifulSoup
from yattag import Doc

# The two main cookies used by jianshou.
# cookie = res.headers['Set-Cookie']
# cookie_dict = session.cookies.get_dict()
# print({
# 	"XSRF-TOKEN": cookie_dict['XSRF-TOKEN'],
# 	"pro_session": cookie_dict['pro_session']
# })

# The header is optional and jianshou APIs works fine without it.
# headers = {
# 	"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:97.0) Gecko/20100101 Firefox/97.0",
# 	"Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,*/*;q=0.8",
# 	"Accept-Language": "en-US,en;q=0.5",
# 	"Accept-Encoding": "gzip, deflate, br",
# 	"Content-Type": "application/x-www-form-urlencoded",
# 	"Origin": "https://jianshou.online",
# 	"Connection": "keep-alive",
# 	"Upgrade-Insecure-Requests": "1",
# 	"Sec-Fetch-Dest": "document",
# 	"Sec-Fetch-Mode": "navigate",
# 	"Sec-Fetch-Site": "same-origin",
# 	"Sec-Fetch-User": "?1",
# 	"Sec-GPC": "1"
# }

class JianshouItem:
	def __init__(self, hashid, name=None, intro=None, content=None, price=None, stock=None):
		self.name = name
		self.intro = intro
		self.hashid = hashid
		self.content = content
		self.price = price
		self.stock = stock
		self.selling_link = f"https://jianshou.online/dashboard/snippet/{hashid}"

class JianshouClient:
	def __init__(self, email, passwd):
		if email is None or passwd is None:
			raise Exception("Email and password are required.")

		self.session = requests.Session()
		res = self.session.get('https://jianshou.online/login')
		html = res.content
		token = self._find_token(html)

		res = self.session.post('https://jianshou.online/login', data={
			'_token': token,
			'email': email, 
			'password': passwd
		})

		assert res.status_code == 200

		# Make sure the login is successful.
		if not self.is_logged_in():
			raise Exception("Login failed")

		# Find all items for sale and store them in a map.
		self.item_map = {}
		for item in self.find_items():
			self.item_map[item.hashid] = item
	
	def is_logged_in(self):
		res = self.session.get('https://jianshou.online/dashboard/snippet/index')
		html = res.content
		soup = BeautifulSoup(html, 'html.parser')
		tbodies = soup.find_all('tbody')
		if len(tbodies) == 0:
			return False
		else:
			return True

	def _find_token(self, html):
		soup = BeautifulSoup(html, 'html.parser')
		inputs = soup.find_all("input", attrs={"name": "_token"})
		if len(inputs) == 0:
			return None
		token = inputs[0]['value']
		return token

	# A paragraph of text followed by external links and images.
	def gen_typical_html_snippet(self, paragraph, image_links=[], other_links=[]):
		doc, tag, text = Doc().tagtext()
		with tag('p'):
			text(paragraph)
			if len(other_links) > 0:
				text("\nOther external links:\n")
				for link in other_links:
					with tag('p'):
						with tag('a', href=link):
							text(link)
		with tag('p'):
			if len(image_links) > 0:
				for link in image_links:
					doc.stag('img', src=link)

		html_snippet = doc.getvalue()
		return html_snippet

	def gen_video_html_snippet(self, video_link):
		doc, tag, text = Doc().tagtext()
		with tag('video', width="100%", height="100%", controls="controls"):
			doc.stag('source', src=video_link, type="video/mp4")
			with tag('p'):
				text("Video not supported by your browser.")
				with tag('a', href=video_link):
					text("Click here to open and download.")

		html_snippet = doc.getvalue()
		return html_snippet

	def refresh(self):
		new_item_map = {}
		for item in self.find_items():
			hashid = item.hashid
			new_item_map[hashid] = item
		self.item_map = new_item_map

	def find_items(self):
		items = []
		res = self.session.get('https://jianshou.online/dashboard/snippet/index')
		html = res.content
		soup = BeautifulSoup(html, 'html.parser')
		tbodies = soup.find_all('tbody')

		if len(tbodies) == 0:
			return []

		# Only hashid and name are available on index page
		tbody = tbodies[0]
		trs = tbody.find_all('tr')
		for tr in trs:
			tds = tr.find_all('td')
			hashid = tds[0].text.strip()
			name = tds[1].text.strip()
			# TODO: Add more properties
			item = JianshouItem(hashid, name=name)
			items.append(item)

		return items

	def upload(self, name=None, intro=None, content=None, price=1, stock=0):
		res = self.session.get('https://jianshou.online/dashboard/snippet/create')
		html = res.content
		token = self._find_token(html)

		data = {
			"_token": token,
			"name": name,
			"intro": intro,
			"type": "1",
			"content": content,
			"price": price,
			"stock": stock,
		}

		res = self.session.post('https://jianshou.online/dashboard/snippet/store', data=data)
		assert res.status_code == 200
		hashid = res.url.split('/')[-1]
		self.refresh()
		return self.item_map[hashid]

	def update_baseinfo(self, hashid, new_name=None, new_intro=None):
		if hashid not in self.item_map:
			print("Item not found by hashid %s" % hashid)
			return

		# TODO: Find name and intro from base info page
		baseinfo_url = format("https://jianshou.online/dashboard/snippet/%s/baseinfo" % hashid)
		res = self.session.get(baseinfo_url)
		html = res.content
		token = self._find_token(html)

		# The properties have to be set in the exact order below
		data = {
			"_method": "patch",
			"_token": token,
			"name": new_name if new_name else self.item_map[hashid].name,
			"intro": new_intro if new_intro else self.item_map[hashid].intro,
		}

		res = self.session.post(baseinfo_url, data=data)
		self.refresh()
		assert res.status_code == 200
		# print("Update basic info with status code: " + str(res.status_code))
		return self.item_map[hashid]

	def update_payinfo(self, hashid, new_price=None, new_stock=None, new_content=None):
		if hashid not in self.item_map:
			print("Item not found by hashid %s" % hashid)
			return

		# TODO: Find content, price and stock from pay info page
		payinfo_url = format("https://jianshou.online/dashboard/snippet/%s/payinfo" % hashid)
		res = self.session.get(payinfo_url)
		html = res.content
		token = self._find_token(html)

		# The properties have to be set in the exact order below
		data = {
			"_method": "patch",
			"_token": token,
			"content": new_content if new_content else self.item_map[hashid].content,
			"price": str(new_price) if new_price else str(self.item_map[hashid].price),
			"stock": str(new_stock) if new_stock else str(self.item_map[hashid].stock),
		}

		res = self.session.post(payinfo_url, data=data)
		self.refresh()
		assert res.status_code == 200
		# print("Update pay info with status code: " + str(res.status_code))
		return self.item_map[hashid]

	def delete(self, hashid):
		if hashid not in self.item_map:
			print("Item not found by hashid %s" % hashid)
			return

		deleted_item = self.item_map[hashid]
		resource_url = format("https://jianshou.online/dashboard/snippet/%s" % hashid)
		res = self.session.get(resource_url)
		html = res.content
		token = self._find_token(html)

		res = self.session.post(resource_url, data={
			'_token': token,
			'_method': 'delete',
		})

		self.refresh()
		assert res.status_code == 200
		return deleted_item