# Copyright (c) 2020, JINGROW
# License: MIT. See LICENSE

from typing import TYPE_CHECKING

import jingrow
from jingrow.desk.utils import slug
from jingrow.model.page import Page

if TYPE_CHECKING:
	from jingrow.core.pagetype.pagefield.pagefield import PageField


class PageTypeLayout(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.custom.pagetype.pagetype_layout_field.pagetype_layout_field import PageTypeLayoutField
		from jingrow.types import DF

		client_script: DF.Code | None
		document_type: DF.Link
		fields: DF.Table[PageTypeLayoutField]
		route: DF.Data

	# end: auto-generated types
	def validate(self):
		if not self.route:
			self.route = slug(self.name)

	@jingrow.whitelist()
	def sync_fields(self):
		pagetype_fields = jingrow.get_meta(self.document_type, cached=False).fields

		if self.is_new():
			added_fields = [field.fieldname for field in pagetype_fields]
			removed_fields = []
		else:
			pagetype_fieldnames = {field.fieldname for field in pagetype_fields}
			layout_fieldnames = {field.fieldname for field in self.fields}
			added_fields = list(pagetype_fieldnames - layout_fieldnames)
			removed_fields = list(layout_fieldnames - pagetype_fieldnames)

		if not (added_fields or removed_fields):
			return

		added = self.add_fields(added_fields, pagetype_fields)
		removed = self.remove_fields(removed_fields)

		for index, field in enumerate(self.fields):
			field.idx = index + 1

		return {"added": added, "removed": removed}

	def add_fields(self, added_fields: list[str], pagetype_fields: list["PageField"]) -> list[dict]:
		added = []
		for field in added_fields:
			field_details = next((f for f in pagetype_fields if f.fieldname == field), None)
			if not field_details:
				continue

			# remove 'pagetype' data from the PageField to allow adding it to the layout
			row = self.append("fields", field_details.as_dict(no_default_fields=True))
			row_data = row.as_dict()

			if field_details.get("insert_after"):
				insert_after = next(
					(f for f in self.fields if f.fieldname == field_details.insert_after),
					None,
				)

				# initialize new row to just after the insert_after field
				if insert_after:
					self.fields.insert(insert_after.idx, row)
					self.fields.pop()

					row_data = {"idx": insert_after.idx + 1, "fieldname": row.fieldname, "label": row.label}

			added.append(row_data)
		return added

	def remove_fields(self, removed_fields: list[str]) -> list[dict]:
		removed = []
		for field in removed_fields:
			field_details = next((f for f in self.fields if f.fieldname == field), None)
			if field_details:
				self.remove(field_details)
				removed.append(field_details.as_dict())
		return removed
