# Copyright (c) 2018, XhiveFramework Technologies and contributors
# License: MIT. See LICENSE


import json

import xhiveframework
from xhiveframework.desk.form.load import get_attachments
from xhiveframework.desk.query_report import generate_report_result
from xhiveframework.model.document import Document
from xhiveframework.monitor import add_data_to_monitor
from xhiveframework.utils import gzip_compress, gzip_decompress
from xhiveframework.utils.background_jobs import enqueue


class PreparedReport(Document):
	def before_insert(self):
		self.status = "Queued"
		self.report_start_time = xhiveframework.utils.now()

	def enqueue_report(self):
		enqueue(run_background, prepared_report=self.name, timeout=6000)


def run_background(prepared_report):
	instance = xhiveframework.get_doc("Prepared Report", prepared_report)
	report = xhiveframework.get_doc("Report", instance.ref_report_doctype)

	add_data_to_monitor(report=instance.ref_report_doctype)

	try:
		report.custom_columns = []

		if report.report_type == "Custom Report":
			custom_report_doc = report
			reference_report = custom_report_doc.reference_report
			report = xhiveframework.get_doc("Report", reference_report)
			if custom_report_doc.json:
				data = json.loads(custom_report_doc.json)
				if data:
					report.custom_columns = data["columns"]

		result = generate_report_result(report=report, filters=instance.filters, user=instance.owner)
		create_json_gz_file(result["result"], "Prepared Report", instance.name)

		instance.status = "Completed"
		instance.columns = json.dumps(result["columns"])
		instance.report_end_time = xhiveframework.utils.now()
		instance.save(ignore_permissions=True)

	except Exception:
		report.log_error("Prepared report failed")
		instance = xhiveframework.get_doc("Prepared Report", prepared_report)
		instance.status = "Error"
		instance.error_message = xhiveframework.get_traceback()
		instance.save(ignore_permissions=True)

	xhiveframework.publish_realtime(
		"report_generated",
		{"report_name": instance.report_name, "name": instance.name},
		user=xhiveframework.session.user,
	)


@xhiveframework.whitelist()
def get_reports_in_queued_state(report_name, filters):
	reports = xhiveframework.get_all(
		"Prepared Report",
		filters={
			"report_name": report_name,
			"filters": process_filters_for_prepared_report(filters),
			"status": "Queued",
		},
	)
	return reports


def delete_expired_prepared_reports():
	system_settings = xhiveframework.get_single("System Settings")
	enable_auto_deletion = system_settings.enable_prepared_report_auto_deletion
	if enable_auto_deletion:
		expiry_period = system_settings.prepared_report_expiry_period
		prepared_reports_to_delete = xhiveframework.get_all(
			"Prepared Report",
			filters={"creation": ["<", xhiveframework.utils.add_days(xhiveframework.utils.now(), -expiry_period)]},
		)

		batches = xhiveframework.utils.create_batch(prepared_reports_to_delete, 100)
		for batch in batches:
			args = {
				"reports": batch,
			}
			enqueue(method=delete_prepared_reports, job_name="delete_prepared_reports", **args)


@xhiveframework.whitelist()
def delete_prepared_reports(reports):
	reports = xhiveframework.parse_json(reports)
	for report in reports:
		xhiveframework.delete_doc(
			"Prepared Report", report["name"], ignore_permissions=True, delete_permanently=True
		)


def process_filters_for_prepared_report(filters):
	if isinstance(filters, str):
		filters = json.loads(filters)

	# This looks like an insanity but, without this it'd be very hard to find Prepared Reports matching given condition
	# We're ensuring that spacing is consistent. e.g. JS seems to put no spaces after ":", Python on the other hand does.
	# We are also ensuring that order of keys is same so generated JSON string will be identical too.
	# PS: xhiveframework.as_json sorts keys
	return xhiveframework.as_json(filters, indent=None, separators=(",", ":"))


def create_json_gz_file(data, dt, dn):
	# Storing data in CSV file causes information loss
	# Reports like P&L Statement were completely unsuable because of this
	json_filename = "{}.json.gz".format(
		xhiveframework.utils.data.format_datetime(xhiveframework.utils.now(), "Y-m-d-H:M")
	)
	encoded_content = xhiveframework.safe_encode(xhiveframework.as_json(data))
	compressed_content = gzip_compress(encoded_content)

	# Call save() file function to upload and attach the file
	_file = xhiveframework.get_doc(
		{
			"doctype": "File",
			"file_name": json_filename,
			"attached_to_doctype": dt,
			"attached_to_name": dn,
			"content": compressed_content,
			"is_private": 1,
		}
	)
	_file.save(ignore_permissions=True)


@xhiveframework.whitelist()
def download_attachment(dn):
	attachment = get_attachments("Prepared Report", dn)[0]
	xhiveframework.local.response.filename = attachment.file_name[:-2]
	attached_file = xhiveframework.get_doc("File", attachment.name)
	xhiveframework.local.response.filecontent = gzip_decompress(attached_file.get_content())
	xhiveframework.local.response.type = "binary"


def get_permission_query_condition(user):
	if not user:
		user = xhiveframework.session.user
	if user == "Administrator":
		return None

	from xhiveframework.utils.user import UserPermissions

	user = UserPermissions(user)

	if "System Manager" in user.roles:
		return None

	reports = [xhiveframework.db.escape(report) for report in user.get_all_reports().keys()]

	return """`tabPrepared Report`.ref_report_doctype in ({reports})""".format(
		reports=",".join(reports)
	)


def has_permission(doc, user):
	if not user:
		user = xhiveframework.session.user
	if user == "Administrator":
		return True

	from xhiveframework.utils.user import UserPermissions

	user = UserPermissions(user)

	if "System Manager" in user.roles:
		return True

	return doc.ref_report_doctype in user.get_all_reports().keys()
