# Copyright (c) 2019, JINGROW
# License: MIT. See LICENSE

import jingrow
from jingrow.model.page import Page
from jingrow.query_builder import PageType
from jingrow.utils import unique


class Tag(Page):
	# begin: auto-generated types
	# This code is auto-generated. Do not modify anything in this block.

	from typing import TYPE_CHECKING

	if TYPE_CHECKING:
		from jingrow.types import DF

		description: DF.SmallText | None
	# end: auto-generated types
	pass


def check_user_tags(dt):
	"if the user does not have a tags column, then it creates one"
	try:
		pagetype = PageType(dt)
		jingrow.qb.from_(pagetype).select(pagetype._user_tags).limit(1).run()
	except Exception as e:
		if jingrow.db.is_missing_column(e):
			DocTags(dt).setup()


@jingrow.whitelist()
def add_tag(tag, dt, dn, color=None):
	"adds a new tag to a record, and creates the Tag master"
	DocTags(dt).add(dn, tag)

	return tag


@jingrow.whitelist()
def add_tags(tags, dt, pgs, color=None):
	"adds a new tag to a record, and creates the Tag master"
	tags = jingrow.parse_json(tags)
	pgs = jingrow.parse_json(pgs)
	for pg in pgs:
		for tag in tags:
			DocTags(dt).add(pg, tag)


@jingrow.whitelist()
def remove_tag(tag, dt, dn):
	"removes tag from the record"
	DocTags(dt).remove(dn, tag)


@jingrow.whitelist()
def get_tagged_pgs(pagetype, tag):
	jingrow.has_permission(pagetype, throw=True)
	pagetype = PageType(pagetype)
	return (jingrow.qb.from_(pagetype).where(pagetype._user_tags.like(tag)).select(pagetype.name)).run()


@jingrow.whitelist()
def get_tags(pagetype, txt):
	tag = jingrow.get_list("Tag", filters=[["name", "like", f"%{txt}%"]])
	tags = [t.name for t in tag]

	return sorted(filter(lambda t: t and txt.casefold() in t.casefold(), list(set(tags))))


class DocTags:
	"""Tags for a particular pagetype"""

	def __init__(self, dt):
		self.dt = dt

	def get_tag_fields(self):
		"""returns tag_fields property"""
		return jingrow.db.get_value("PageType", self.dt, "tag_fields")

	def get_tags(self, dn):
		"""returns tag for a particular item"""
		return (jingrow.db.get_value(self.dt, dn, "_user_tags", ignore=1) or "").strip()

	def add(self, dn, tag):
		"""add a new user tag"""
		tl = self.get_tags(dn).split(",")
		if tag not in tl:
			tl.append(tag)
			if not jingrow.db.exists("Tag", tag):
				jingrow.get_pg({"pagetype": "Tag", "name": tag}).insert(ignore_permissions=True)
			self.update(dn, tl)

	def remove(self, dn, tag):
		"""remove a user tag"""
		tl = self.get_tags(dn).split(",")
		self.update(dn, filter(lambda x: x.lower() != tag.lower(), tl))

	def remove_all(self, dn):
		"""remove all user tags (call before delete)"""
		self.update(dn, [])

	def update(self, dn, tl):
		"""updates the _user_tag column in the table"""

		if not tl:
			tags = ""
		else:
			tl = unique(filter(lambda x: x, tl))
			tags = "," + ",".join(tl)
		try:
			jingrow.db.sql(
				"update `tab{}` set _user_tags={} where name={}".format(self.dt, "%s", "%s"), (tags, dn)
			)
			pg = jingrow.get_pg(self.dt, dn)
			update_tags(pg, tags)
		except Exception as e:
			if jingrow.db.is_missing_column(e):
				if not tags:
					# no tags, nothing to do
					return

				self.setup()
				self.update(dn, tl)
			else:
				raise

	def setup(self):
		"""adds the _user_tags column if not exists"""
		from jingrow.database.schema import add_column

		add_column(self.dt, "_user_tags", "Data")


def delete_tags_for_document(pg):
	"""
	Delete the Tag Link entry of a document that has
	been deleted
	:param pg: Deleted document
	"""
	if not jingrow.db.table_exists("Tag Link"):
		return

	jingrow.db.delete("Tag Link", {"document_type": pg.pagetype, "document_name": pg.name})


def update_tags(pg, tags):
	"""Adds tags for documents

	:param pg: Page to be added to global tags
	"""
	pg.check_permission("write")
	new_tags = {tag.strip() for tag in tags.split(",") if tag}
	existing_tags = [
		tag.tag
		for tag in jingrow.get_list(
			"Tag Link", filters={"document_type": pg.pagetype, "document_name": pg.name}, fields=["tag"]
		)
	]

	added_tags = set(new_tags) - set(existing_tags)
	for tag in added_tags:
		jingrow.get_pg(
			{
				"pagetype": "Tag Link",
				"document_type": pg.pagetype,
				"document_name": pg.name,
				"title": pg.get_title() or "",
				"tag": tag,
			}
		).insert(ignore_permissions=True)

	deleted_tags = list(set(existing_tags) - set(new_tags))
	for tag in deleted_tags:
		jingrow.db.delete("Tag Link", {"document_type": pg.pagetype, "document_name": pg.name, "tag": tag})


@jingrow.whitelist()
def get_documents_for_tag(tag):
	"""
	Search for given text in Tag Link
	:param tag: tag to be searched
	"""
	# remove hastag `#` from tag
	tag = tag[1:]

	result = jingrow.get_list(
		"Tag Link", filters={"tag": tag}, fields=["document_type", "document_name", "title", "tag"]
	)

	return [
		{
			"pagetype": res.document_type,
			"name": res.document_name,
			"content": res.title,
		}
		for res in result
	]


@jingrow.whitelist()
def get_tags_list_for_awesomebar():
	return jingrow.get_list("Tag", pluck="name", order_by=None)
