"""Auto-match Bank Integration registry rows to ERPNext Customer/Supplier/Bank Account."""

from difflib import SequenceMatcher

import frappe
from frappe.utils import flt


_AZERI_MAP = str.maketrans("ƏəÜüÖöĞğİıÇçŞş", "EeUuOoGgIiCcSs")


def _normalize(text, consider_azeri=True):
	if not text:
		return ""
	s = str(text)
	if consider_azeri:
		s = s.translate(_AZERI_MAP)
	return " ".join(s.lower().split())


@frappe.whitelist()
def match_similar_customers(bank_integration):
	"""Auto-match BI Customers to ERPNext Customers by VOEN or name similarity."""
	bi = frappe.get_doc("Bank Statement Importer", bank_integration)
	threshold = flt(bi.similarity_threshold_customers or 90) / 100.0
	consider_azeri = bool(bi.consider_azeri_chars)

	new_customers = frappe.get_all(
		"Bank Integration Customer",
		filters={"status": "New", "parent_bank_integration": bank_integration},
		fields=["name", "customer_name", "tax_id"],
	)
	if not new_customers:
		return {"success": True, "matched_count": 0, "total_processed": 0}

	erp_customers = frappe.get_all("Customer", fields=["name", "customer_name", "tax_id"])
	voen_index = {c.tax_id.strip(): c.name for c in erp_customers if c.tax_id}

	existing_mappings = {row.bi_customer_name: row.erp_customer for row in bi.customer_mappings if row.bi_customer_name}

	to_process = []
	for c in new_customers:
		if c.name in existing_mappings:
			if not existing_mappings[c.name]:
				to_process.append(c)
		else:
			to_process.append(c)

	matched = 0
	for cust in to_process:
		best_party = None

		if cust.tax_id and cust.tax_id.strip() in voen_index:
			best_party = voen_index[cust.tax_id.strip()]
		else:
			kb_name = _normalize(cust.customer_name, consider_azeri)
			best_score = 0
			for c in erp_customers:
				score = SequenceMatcher(None, kb_name, _normalize(c.customer_name, consider_azeri)).ratio()
				if score > best_score:
					best_score = score
					best_party = c.name
			if best_score < threshold:
				best_party = None

		if best_party:
			_set_mapping_row(bi, "customer_mappings", "bi_customer_name", cust.name,
				{"erp_customer": best_party, "tax_id": cust.tax_id or None, "mapping_type": "Automatic"})
			frappe.db.set_value("Bank Integration Customer", cust.name, {
				"mapped_customer": best_party,
				"status": "Mapped",
			}, update_modified=False)
			matched += 1

	if matched > 0:
		bi.save(ignore_permissions=True)
	frappe.db.commit()
	return {"success": True, "matched_count": matched, "total_processed": len(to_process)}


@frappe.whitelist()
def match_similar_suppliers(bank_integration):
	bi = frappe.get_doc("Bank Statement Importer", bank_integration)
	threshold = flt(bi.similarity_threshold_suppliers or 80) / 100.0
	consider_azeri = bool(bi.consider_azeri_chars)

	new_suppliers = frappe.get_all(
		"Bank Integration Supplier",
		filters={"status": "New", "parent_bank_integration": bank_integration},
		fields=["name", "supplier_name", "tax_id"],
	)
	if not new_suppliers:
		return {"success": True, "matched_count": 0, "total_processed": 0}

	erp_suppliers = frappe.get_all("Supplier", fields=["name", "supplier_name", "tax_id"])
	voen_index = {s.tax_id.strip(): s.name for s in erp_suppliers if s.tax_id}

	existing_mappings = {row.bi_supplier_name: row.erp_supplier for row in bi.supplier_mappings if row.bi_supplier_name}

	to_process = []
	for s in new_suppliers:
		if s.name in existing_mappings:
			if not existing_mappings[s.name]:
				to_process.append(s)
		else:
			to_process.append(s)

	matched = 0
	for supp in to_process:
		best_party = None

		if supp.tax_id and supp.tax_id.strip() in voen_index:
			best_party = voen_index[supp.tax_id.strip()]
		else:
			kb_name = _normalize(supp.supplier_name, consider_azeri)
			best_score = 0
			for s in erp_suppliers:
				score = SequenceMatcher(None, kb_name, _normalize(s.supplier_name, consider_azeri)).ratio()
				if score > best_score:
					best_score = score
					best_party = s.name
			if best_score < threshold:
				best_party = None

		if best_party:
			_set_mapping_row(bi, "supplier_mappings", "bi_supplier_name", supp.name,
				{"erp_supplier": best_party, "tax_id": supp.tax_id or None, "mapping_type": "Automatic"})
			frappe.db.set_value("Bank Integration Supplier", supp.name, {
				"mapped_supplier": best_party,
				"status": "Mapped",
			}, update_modified=False)
			matched += 1

	if matched > 0:
		bi.save(ignore_permissions=True)
	frappe.db.commit()
	return {"success": True, "matched_count": matched, "total_processed": len(to_process)}


def _set_mapping_row(bi, table_field, key_field, key_value, values):
	"""Update an existing child row matching key_field=key_value, or append new."""
	for row in bi.get(table_field):
		if row.get(key_field) == key_value:
			for k, v in values.items():
				row.set(k, v)
			return
	bi.append(table_field, dict({key_field: key_value}, **values))
