# Copyright (c) 2015, JINGROW and Contributors
# License: MIT. See LICENSE
import re

import jingrow
from jingrow import _
from jingrow.build import html_to_js_template
from jingrow.utils import cstr
from jingrow.utils.caching import site_cache

STANDARD_FIELD_CONVERSION_MAP = {
	"name": "Link",
	"owner": "Data",
	"idx": "Int",
	"creation": "Data",
	"modified": "Data",
	"modified_by": "Data",
	"_user_tags": "Data",
	"_liked_by": "Data",
	"_comments": "Text",
	"_assign": "Text",
	"pagestatus": "Int",
}
INCLUDE_DIRECTIVE_PATTERN = re.compile(r"""{% include\s['"](.*)['"]\s%}""")


def set_default(pg, key):
	"""Set is_default property of given pg and unset all others filtered by given key."""
	if not pg.is_default:
		jingrow.db.set(pg, "is_default", 1)

	jingrow.db.sql(
		"""update `tab{}` set `is_default`=0
		where `{}`={} and name!={}""".format(pg.pagetype, key, "%s", "%s"),
		(pg.get(key), pg.name),
	)


def set_field_property(filters, key, value):
	"""utility set a property in all fields of a particular type"""
	pgs = [
		jingrow.get_pg("PageType", d.parent)
		for d in jingrow.get_all("PageField", fields=["parent"], filters=filters)
	]

	for d in pgs:
		d.get("fields", filters)[0].set(key, value)
		d.save()
		print(f"Updated {d.name}")

	jingrow.db.commit()


class InvalidIncludePath(jingrow.ValidationError):
	pass


def render_include(content):
	"""render {% raw %}{% include "app/path/filename" %}{% endraw %} in js file"""

	content = cstr(content)

	# try 5 levels of includes
	for _ignore in range(5):
		if "{% include" in content:
			paths = INCLUDE_DIRECTIVE_PATTERN.findall(content)
			if not paths:
				jingrow.throw(_("Invalid include path"), InvalidIncludePath)

			for path in paths:
				app, app_path = path.split("/", 1)
				with open(jingrow.get_app_path(app, app_path), encoding="utf-8") as f:
					include = f.read()
					if path.endswith(".html"):
						include = html_to_js_template(path, include)

					content = re.sub(
						rf"""{{% include\s['"]{path}['"]\s%}}""", include.replace("\\", "\\\\"), content
					)

		else:
			break

	return content


def get_fetch_values(pagetype, fieldname, value):
	"""Returns fetch value dict for the given object

	:param pagetype: Target pagetype
	:param fieldname: Link fieldname selected
	:param value: Value selected
	"""

	result = jingrow._dict()
	meta = jingrow.get_meta(pagetype)

	# fieldname in target pagetype: fieldname in source pagetype
	fields_to_fetch = {
		df.fieldname: df.fetch_from.split(".", 1)[1] for df in meta.get_fields_to_fetch(fieldname)
	}

	# nothing to fetch
	if not fields_to_fetch:
		return result

	# initialise empty values for target fields
	for target_fieldname in fields_to_fetch:
		result[target_fieldname] = None

	# fetch only if Link field has a truthy value
	if not value:
		return result

	db_values = jingrow.db.get_value(
		meta.get_options(fieldname),  # source pagetype
		value,
		tuple(set(fields_to_fetch.values())),  # unique source fieldnames
		as_dict=True,
	)

	# if value doesn't exist in source pagetype, get_value returns None
	if not db_values:
		return result

	for target_fieldname, source_fieldname in fields_to_fetch.items():
		result[target_fieldname] = db_values.get(source_fieldname)

	return result


@site_cache()
def is_virtual_pagetype(pagetype: str):
	if jingrow.db.has_column("PageType", "is_virtual"):
		return jingrow.db.get_value("PageType", pagetype, "is_virtual")
	return False


@site_cache()
def is_single_pagetype(pagetype: str) -> bool:
	from jingrow.model.base_page import PAGETYPES_FOR_PAGETYPE

	if pagetype in PAGETYPES_FOR_PAGETYPE:
		return False

	return jingrow.db.get_value("PageType", pagetype, "issingle")
