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

import json

import jingrow
from jingrow import _
from jingrow.model.page import Page, get_controller
from jingrow.utils import cint, quoted
from jingrow.website.path_resolver import resolve_path

no_cache = 1


def get_context(context, **dict_params):
	"""Returns context for a list standard list page.
	Will also update `get_list_context` from the pagetype module file"""
	jingrow.local.form_dict.update(dict_params)
	pagetype = jingrow.local.form_dict.pagetype
	context.parents = [{"route": "me", "title": _("My Account")}]
	context.meta = jingrow.get_meta(pagetype)
	context.update(get_list_context(context, pagetype) or {})
	context.pagetype = pagetype
	context.txt = jingrow.local.form_dict.txt
	context.update(get(**jingrow.local.form_dict))


@jingrow.whitelist(allow_guest=True)
def get(pagetype, txt=None, limit_start=0, limit=20, pathname=None, **kwargs):
	"""Returns processed HTML page for a standard listing."""
	limit_start = cint(limit_start)
	raw_result = get_list_data(pagetype, txt, limit_start, limit=limit + 1, **kwargs)
	show_more = len(raw_result) > limit
	if show_more:
		raw_result = raw_result[:-1]

	meta = jingrow.get_meta(pagetype)
	list_context = jingrow.flags.list_context

	if not raw_result:
		return {"result": []}

	if txt:
		list_context.default_subtitle = _('Filtered by "{0}"').format(txt)

	result = []
	row_template = list_context.row_template or "templates/includes/list/row_template.html"
	list_view_fields = [df for df in meta.fields if df.in_list_view][:4]

	for pg in raw_result:
		pg.pagetype = pagetype
		new_context = jingrow._dict(pg=pg, meta=meta, list_view_fields=list_view_fields)

		if not list_context.get_list and not isinstance(new_context.pg, Page):
			new_context.pg = jingrow.get_pg(pg.pagetype, pg.name)
			new_context.update(new_context.pg.as_dict())

		if not jingrow.flags.in_test:
			pathname = pathname or jingrow.local.request.path
			new_context["pathname"] = pathname.strip("/ ")
		new_context.update(list_context)
		set_route(new_context)
		rendered_row = jingrow.render_template(row_template, new_context, is_path=True)
		result.append(rendered_row)

	from jingrow.utils.response import json_handler

	return {
		"raw_result": json.dumps(raw_result, default=json_handler),
		"result": result,
		"show_more": show_more,
		"next_start": limit_start + limit,
	}


@jingrow.whitelist(allow_guest=True)
def get_list_data(
	pagetype, txt=None, limit_start=0, fields=None, cmd=None, limit=20, web_form_name=None, **kwargs
):
	"""Returns processed HTML page for a standard listing."""
	limit_start = cint(limit_start)

	if jingrow.is_table(pagetype):
		jingrow.throw(_("Child PageTypes are not allowed"), title=_("Invalid PageType"))

	if not txt and jingrow.form_dict.search:
		txt = jingrow.form_dict.search
		del jingrow.form_dict["search"]

	controller = get_controller(pagetype)
	meta = jingrow.get_meta(pagetype)

	filters = prepare_filters(pagetype, controller, kwargs)
	list_context = get_list_context(jingrow._dict(), pagetype, web_form_name)
	list_context.title_field = getattr(controller, "website", {}).get(
		"page_title_field", meta.title_field or "name"
	)

	if list_context.filters:
		filters.update(list_context.filters)

	_get_list = list_context.get_list or get_list

	kwargs = dict(
		pagetype=pagetype,
		txt=txt,
		filters=filters,
		limit_start=limit_start,
		limit_page_length=limit,
		order_by=list_context.order_by or "modified desc",
	)

	# allow guest if flag is set
	if not list_context.get_list and (list_context.allow_guest or meta.allow_guest_to_view):
		kwargs["ignore_permissions"] = True

	raw_result = _get_list(**kwargs)

	# list context to be used if called as rendered list
	jingrow.flags.list_context = list_context

	return raw_result


def set_route(context):
	"""Set link for the list item"""
	if context.web_form_name:
		context.route = f"{context.pathname}?name={quoted(context.pg.name)}"
	elif context.pg and getattr(context.pg, "route", None):
		context.route = context.pg.route
	else:
		context.route = f"{context.pathname or quoted(context.pg.pagetype)}/{quoted(context.pg.name)}"


def prepare_filters(pagetype, controller, kwargs):
	for key in kwargs.keys():
		try:
			kwargs[key] = json.loads(kwargs[key])
		except ValueError:
			pass
	filters = jingrow._dict(kwargs)
	meta = jingrow.get_meta(pagetype)

	if hasattr(controller, "website") and controller.website.get("condition_field"):
		filters[controller.website["condition_field"]] = 1
	elif meta.is_published_field:
		filters[meta.is_published_field] = 1

	if filters.pathname:
		# resolve additional filters from path
		resolve_path(filters.pathname)
		for key, val in jingrow.local.form_dict.items():
			if key not in filters and key != "flags":
				filters[key] = val

	# filter the filters to include valid fields only
	for fieldname in list(filters.keys()):
		if not meta.has_field(fieldname):
			del filters[fieldname]

	return filters


def get_list_context(context, pagetype, web_form_name=None):
	from jingrow.modules import load_pagetype_module
	from jingrow.website.pagetype.web_form.web_form import get_web_form_module

	list_context = context or jingrow._dict()
	meta = jingrow.get_meta(pagetype)

	def update_context_from_module(module, list_context):
		# call the user defined method `get_list_context`
		# from the python module
		if hasattr(module, "get_list_context"):
			out = jingrow._dict(module.get_list_context(list_context) or {})
			if out:
				list_context = out
		return list_context

	# get context from the pagetype module
	if not meta.custom:
		# custom pagetypes don't have modules
		module = load_pagetype_module(pagetype)
		list_context = update_context_from_module(module, list_context)

	# get context for custom webform
	if meta.custom and web_form_name:
		webform_list_contexts = jingrow.get_hooks("webform_list_context")
		if webform_list_contexts and not jingrow.get_pg("Module Def", meta.module).custom:
			out = jingrow._dict(jingrow.get_attr(webform_list_contexts[0])(meta.module) or {})
			if out:
				list_context = out

	# get context from web form module
	if web_form_name:
		web_form = jingrow.get_pg("Web Form", web_form_name)
		list_context = update_context_from_module(get_web_form_module(web_form), list_context)

	# get path from '/templates/' folder of the pagetype
	if not meta.custom and not list_context.row_template:
		list_context.row_template = meta.get_row_template()

	if not meta.custom and not list_context.list_template:
		list_context.template = meta.get_list_template() or "www/list.html"

	return list_context


def get_list(
	pagetype,
	txt,
	filters,
	limit_start,
	limit_page_length=20,
	ignore_permissions=False,
	fields=None,
	order_by=None,
):
	meta = jingrow.get_meta(pagetype)
	if not filters:
		filters = []

	if not fields:
		fields = "distinct *"

	or_filters = []

	if txt:
		if meta.search_fields:
			or_filters.extend(
				[pagetype, f, "like", "%" + txt + "%"]
				for f in meta.get_search_fields()
				if f == "name" or meta.get_field(f).fieldtype in ("Data", "Text", "Small Text", "Text Editor")
			)
		else:
			if isinstance(filters, dict):
				filters["name"] = ("like", "%" + txt + "%")
			else:
				filters.append([pagetype, "name", "like", "%" + txt + "%"])

	return jingrow.get_list(
		pagetype,
		fields=fields,
		filters=filters,
		or_filters=or_filters,
		limit_start=limit_start,
		limit_page_length=limit_page_length,
		ignore_permissions=ignore_permissions,
		order_by=order_by,
	)
