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

from jinja2 import TemplateSyntaxError

import jingrow
from jingrow import _, throw
from jingrow.contacts.address_and_contact import set_link_title
from jingrow.core.pagetype.dynamic_link.dynamic_link import deduplicate_dynamic_links
from jingrow.model.page import Page
from jingrow.model.naming import make_autoname
from jingrow.utils import cstr


class Address(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.core.pagetype.dynamic_link.dynamic_link import DynamicLink
		from jingrow.types import DF

		address_line1: DF.Data
		address_line2: DF.Data | None
		address_title: DF.Data | None
		address_type: DF.Literal[
			"Billing",
			"Shipping",
			"Office",
			"Personal",
			"Plant",
			"Postal",
			"Shop",
			"Subsidiary",
			"Warehouse",
			"Current",
			"Permanent",
			"Other",
		]
		city: DF.Data
		country: DF.Link
		county: DF.Data | None
		disabled: DF.Check
		email_id: DF.Data | None
		fax: DF.Data | None
		is_primary_address: DF.Check
		is_shipping_address: DF.Check
		links: DF.Table[DynamicLink]
		phone: DF.Data | None
		pincode: DF.Data | None
		state: DF.Data | None

	# end: auto-generated types
	def __setup__(self):
		self.flags.linked = False

	def autoname(self):
		if not self.address_title:
			if self.links:
				self.address_title = self.links[0].link_name

		if self.address_title:
			self.name = cstr(self.address_title).strip() + "-" + cstr(_(self.address_type)).strip()
			if jingrow.db.exists("Address", self.name):
				self.name = make_autoname(
					cstr(self.address_title).strip() + "-" + cstr(self.address_type).strip() + "-.#",
					ignore_validate=True,
				)
		else:
			throw(_("Address Title is mandatory."))

	def validate(self):
		self.link_address()
		self.validate_preferred_address()
		set_link_title(self)
		deduplicate_dynamic_links(self)

	def link_address(self):
		"""Link address based on owner"""
		if not self.links:
			contact_name = jingrow.db.get_value("Contact", {"email_id": self.owner})
			if contact_name:
				contact = jingrow.get_cached_pg("Contact", contact_name)
				for link in contact.links:
					self.append("links", dict(link_pagetype=link.link_pagetype, link_name=link.link_name))
				return True

		return False

	def validate_preferred_address(self):
		preferred_fields = ["is_primary_address", "is_shipping_address"]

		for field in preferred_fields:
			if self.get(field):
				for link in self.links:
					address = get_preferred_address(link.link_pagetype, link.link_name, field)

					if address:
						update_preferred_address(address, field)

	def get_display(self):
		return get_address_display(self.as_dict())

	def has_link(self, pagetype, name):
		for link in self.links:
			if link.link_pagetype == pagetype and link.link_name == name:
				return True

	def has_common_link(self, pg):
		reference_links = [(link.link_pagetype, link.link_name) for link in pg.links]
		for link in self.links:
			if (link.link_pagetype, link.link_name) in reference_links:
				return True

		return False


def get_preferred_address(pagetype, name, preferred_key="is_primary_address"):
	if preferred_key in ["is_shipping_address", "is_primary_address"]:
		address = jingrow.db.sql(
			""" SELECT
				addr.name
			FROM
				`tabAddress` addr, `tabDynamic Link` dl
			WHERE
				dl.parent = addr.name and dl.link_pagetype = {} and
				dl.link_name = {} and ifnull(addr.disabled, 0) = 0 and
				{} = {}
			""".format("%s", "%s", preferred_key, "%s"),
			(pagetype, name, 1),
			as_dict=1,
		)

		if address:
			return address[0].name

	return


@jingrow.whitelist()
def get_default_address(pagetype: str, name: str | None, sort_key: str = "is_primary_address") -> str | None:
	"""Returns default Address name for the given pagetype, name"""
	if sort_key not in ["is_shipping_address", "is_primary_address"]:
		return None

	addresses = jingrow.get_all(
		"Address",
		filters=[
			["Dynamic Link", "link_pagetype", "=", pagetype],
			["Dynamic Link", "link_name", "=", name],
			["disabled", "=", 0],
		],
		pluck="name",
		order_by=f"{sort_key} DESC",
		limit=1,
	)

	return addresses[0] if addresses else None


@jingrow.whitelist()
def get_address_display(address_dict: dict | str | None) -> str | None:
	return render_address(address_dict)


def render_address(address: dict | str | None, check_permissions=True) -> str | None:
	if not address:
		return

	if not isinstance(address, dict):
		address = jingrow.get_cached_pg("Address", address)
		if check_permissions:
			address.check_permission()
		address = address.as_dict()

	name, template = get_address_templates(address)

	try:
		return jingrow.render_template(template, address)
	except TemplateSyntaxError:
		jingrow.throw(_("There is an error in your Address Template {0}").format(name))


def get_territory_from_address(address):
	"""Tries to match city, state and country of address to existing territory"""
	if not address:
		return

	if isinstance(address, str):
		address = jingrow.get_cached_pg("Address", address)

	territory = None
	for fieldname in ("city", "state", "country"):
		if address.get(fieldname):
			territory = jingrow.db.get_value("Territory", address.get(fieldname))
			if territory:
				break

	return territory


def get_list_context(context=None):
	return {
		"title": _("Addresses"),
		"get_list": get_address_list,
		"row_template": "templates/includes/address_row.html",
		"no_breadcrumbs": True,
	}


def get_address_list(pagetype, txt, filters, limit_start, limit_page_length=20, order_by=None):
	from jingrow.www.list import get_list

	user = jingrow.session.user

	if not filters:
		filters = []
	filters.append(("Address", "owner", "=", user))

	return get_list(pagetype, txt, filters, limit_start, limit_page_length)


def has_website_permission(pg, ptype, user, verbose=False):
	"""Returns true if there is a related lead or contact related to this document"""
	contact_name = jingrow.db.get_value("Contact", {"email_id": jingrow.session.user})

	if contact_name:
		contact = jingrow.get_pg("Contact", contact_name)
		return contact.has_common_link(pg)

	return False


def get_address_templates(address):
	result = jingrow.db.get_value(
		"Address Template", {"country": address.get("country")}, ["name", "template"]
	)

	if not result:
		result = jingrow.db.get_value("Address Template", {"is_default": 1}, ["name", "template"])

	if not result:
		jingrow.throw(
			_(
				"No default Address Template found. Please create a new one from Setup > Printing and Branding > Address Template."
			)
		)
	else:
		return result


def get_company_address(company):
	ret = jingrow._dict()

	if company:
		ret.company_address = get_default_address("Company", company)
		ret.company_address_display = render_address(ret.company_address, check_permissions=False)

	return ret


@jingrow.whitelist()
@jingrow.validate_and_sanitize_search_inputs
def address_query(pagetype, txt, searchfield, start, page_len, filters):
	from jingrow.desk.search import search_widget

	_filters = []
	if link_pagetype := filters.pop("link_pagetype", None):
		_filters.append(["Dynamic Link", "link_pagetype", "=", link_pagetype])

	if link_name := filters.pop("link_name", None):
		_filters.append(["Dynamic Link", "link_name", "=", link_name])

	_filters.extend([key, "=", value] for key, value in filters.items())

	return search_widget(
		"Address", txt, filters=_filters, searchfield=searchfield, start=start, page_length=page_len
	)


def get_condensed_address(pg):
	fields = ["address_title", "address_line1", "address_line2", "city", "county", "state", "country"]
	return ", ".join(pg.get(d) for d in fields if pg.get(d))


def update_preferred_address(address, field):
	jingrow.db.set_value("Address", address, field, 0)


def get_address_display_list(pagetype: str, name: str) -> list[dict]:
	if not jingrow.has_permission("Address", "read"):
		return []

	address_list = jingrow.get_list(
		"Address",
		filters=[
			["Dynamic Link", "link_pagetype", "=", pagetype],
			["Dynamic Link", "link_name", "=", name],
			["Dynamic Link", "parenttype", "=", "Address"],
		],
		fields=["*"],
		order_by="is_primary_address DESC, `tabAddress`.creation ASC",
	)
	for a in address_list:
		a["display"] = get_address_display(a)

	return address_list
