import json

from werkzeug.routing import Rule

import xhiveframework
from xhiveframework import _
from xhiveframework.utils.data import sbool


def document_list(doctype: str):
	if xhiveframework.form_dict.get("fields"):
		xhiveframework.form_dict["fields"] = json.loads(xhiveframework.form_dict["fields"])

	# set limit of records for xhiveframework.get_list
	xhiveframework.form_dict.setdefault(
		"limit_page_length",
		xhiveframework.form_dict.limit or xhiveframework.form_dict.limit_page_length or 20,
	)

	# convert strings to native types - only as_dict and debug accept bool
	for param in ["as_dict", "debug"]:
		param_val = xhiveframework.form_dict.get(param)
		if param_val is not None:
			xhiveframework.form_dict[param] = sbool(param_val)

	# evaluate xhiveframework.get_list
	return xhiveframework.call(xhiveframework.client.get_list, doctype, **xhiveframework.form_dict)


def handle_rpc_call(method: str):
	import xhiveframework.handler

	method = method.split("/")[0]  # for backward compatiblity

	xhiveframework.form_dict.cmd = method
	return xhiveframework.handler.handle()


def create_doc(doctype: str):
	data = get_request_form_data()
	data.pop("doctype", None)
	return xhiveframework.new_doc(doctype, **data).insert()


def update_doc(doctype: str, name: str):
	data = get_request_form_data()

	doc = xhiveframework.get_doc(doctype, name, for_update=True)
	if "flags" in data:
		del data["flags"]

	doc.update(data)
	doc.save()

	# check for child table doctype
	if doc.get("parenttype"):
		xhiveframework.get_doc(doc.parenttype, doc.parent).save()

	return doc


def delete_doc(doctype: str, name: str):
	# TODO: child doc handling
	xhiveframework.delete_doc(doctype, name, ignore_missing=False)
	xhiveframework.response.http_status_code = 202
	return "ok"


def read_doc(doctype: str, name: str):
	# Backward compatiblity
	if "run_method" in xhiveframework.form_dict:
		return execute_doc_method(doctype, name)

	doc = xhiveframework.get_doc(doctype, name)
	if not doc.has_permission("read"):
		raise xhiveframework.PermissionError
	doc.apply_fieldlevel_read_permissions()
	return doc


def execute_doc_method(doctype: str, name: str, method: str | None = None):
	method = method or xhiveframework.form_dict.pop("run_method")
	doc = xhiveframework.get_doc(doctype, name)
	doc.is_whitelisted(method)

	if xhiveframework.request.method == "GET":
		if not doc.has_permission("read"):
			xhiveframework.throw(_("Not permitted"), xhiveframework.PermissionError)
		return doc.run_method(method, **xhiveframework.form_dict)

	elif xhiveframework.request.method == "POST":
		if not doc.has_permission("write"):
			xhiveframework.throw(_("Not permitted"), xhiveframework.PermissionError)

		return doc.run_method(method, **xhiveframework.form_dict)


def get_request_form_data():
	if xhiveframework.form_dict.data is None:
		data = xhiveframework.safe_decode(xhiveframework.request.get_data())
	else:
		data = xhiveframework.form_dict.data

	try:
		return xhiveframework.parse_json(data)
	except ValueError:
		return xhiveframework.form_dict


url_rules = [
	Rule("/method/<path:method>", endpoint=handle_rpc_call),
	Rule("/resource/<doctype>", methods=["GET"], endpoint=document_list),
	Rule("/resource/<doctype>", methods=["POST"], endpoint=create_doc),
	Rule("/resource/<doctype>/<path:name>/", methods=["GET"], endpoint=read_doc),
	Rule("/resource/<doctype>/<path:name>/", methods=["PUT"], endpoint=update_doc),
	Rule("/resource/<doctype>/<path:name>/", methods=["DELETE"], endpoint=delete_doc),
	Rule("/resource/<doctype>/<path:name>/", methods=["POST"], endpoint=execute_doc_method),
]
