# Copyright (c) 2023, JINGROW
# For license information, please see license.txt

import json

import jingrow
from jingrow import _
from jingrow.core.pagetype.version.version import get_diff
from jingrow.model.page import Page


class AuditTrail(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

		pagetype_name: DF.Link
		document: DF.DynamicLink
	# end: auto-generated types
	pass

	def validate(self):
		self.validate_pagetype_name()
		self.validate_document()

	def validate_pagetype_name(self):
		if not self.pagetype_name:
			jingrow.throw(_("{} field cannot be empty.").format(jingrow.bold("Pagetype")))

	def validate_document(self):
		if not self.document:
			jingrow.throw(_("{} field cannot be empty.").format(jingrow.bold("Page")))

	@jingrow.whitelist()
	def compare_document(self):
		self.validate()
		amended_document_names = self.get_amended_documents()
		self.amended_pgs = [jingrow.get_pg(self.pagetype_name, name) for name in amended_document_names]
		self.pgs_to_compare = len(self.amended_pgs)
		self.changed, self.row_changed, self.added, self.removed = {}, {}, {}, {}

		for i in range(1, self.pgs_to_compare):
			diff = get_diff(self.amended_pgs[i - 1], self.amended_pgs[i], compare_cancelled=True)
			self.get_diff_grid(i, diff)
			self.get_rows_added_removed_grid(i, diff, "added", self.added)
			self.get_rows_added_removed_grid(i, diff, "removed", self.removed)
			self.get_rows_updated_grid(i, diff)

		return amended_document_names, {
			"changed": self.changed,
			"row_changed": self.row_changed,
			"added": self.added,
			"removed": self.removed,
		}

	def get_amended_documents(self):
		amended_document_names = []
		curr_pg = self.document
		while curr_pg and len(amended_document_names) < 5:
			amended_document_names.append(curr_pg)
			curr_pg = jingrow.db.get_value(self.pagetype_name, curr_pg, "amended_from")
		amended_document_names = amended_document_names[::-1]

		return amended_document_names

	def get_diff_grid(self, i, diff):
		for change in diff.changed:
			fieldname = get_field_label(change[0], pagetype=self.pagetype_name)
			value = change[-1]
			value_list = [""] * self.pgs_to_compare
			self.changed.setdefault(fieldname, value_list)
			self.changed[fieldname][i] = value or ""

			if i == 1:
				value = change[1]
				self.changed[fieldname][i - 1] = value or ""

	def get_rows_added_removed_grid(self, i, diff, key, changed_dict):
		pg_name = self.amended_pgs[i].name
		changed_dict[pg_name] = {}
		for change in diff[key]:
			tablename = get_field_label(change[0], pagetype=self.pagetype_name)
			value_dict = filter_fields_for_gridview(change[-1])
			changed_dict[pg_name].setdefault(tablename, []).append(value_dict)

	def get_rows_updated_grid(self, i, diff):
		for change in diff.row_changed:
			table_name = get_field_label(change[0], pagetype=self.pagetype_name)
			index = change[1]
			self.row_changed.setdefault(table_name, {}).setdefault(index, {})
			for field in change[-1]:
				fieldname = get_field_label(field[0], pagetype=self.pagetype_name, child_field=change[0])
				value = field[-1]
				value_list = [""] * self.pgs_to_compare
				self.row_changed[table_name][index].setdefault(fieldname, value_list)
				self.row_changed[table_name][index][fieldname][i] = value or ""

				if i == 1:
					value = field[1]
					self.row_changed[table_name][index][fieldname][i - 1] = value or ""


def get_field_label(fieldname, pagetype, child_field=None):
	if child_field:
		meta = jingrow.get_meta(pagetype)
		for field in meta.fields:
			if field.fieldname == child_field:
				pagetype = field.options

	meta = jingrow.get_meta(pagetype)
	label = meta.get_label(fieldname)
	if label not in ["No Label", None, ""]:
		return label
	return fieldname


def filter_fields_for_gridview(row):
	grid_row = {}
	meta = jingrow.get_meta(row.pagetype)
	for field in meta.fields:
		if field.in_list_view == 1:
			fieldlabel = get_field_label(field.fieldname, row.pagetype)
			grid_row[fieldlabel] = row[field.fieldname] or ""

	return grid_row
