"""One-time / idempotent migrations for Bank Integration."""

import frappe


def add_importer_link_to_invoicing_workspace():
	"""Insert a 'Bank Statement Importer' link into the existing 'Banking' card
	on the ERPNext 'Invoicing' workspace.

	This intentionally edits an ERPNext-owned workspace at runtime rather than
	overriding its JSON file: ERPNext re-syncs the JSON on every `bench
	migrate`, so any direct file edit would be reverted. We run from
	after_migrate, which fires AFTER that resync, so this stays in place.

	Idempotent — runs every migrate but only inserts when the link is missing.
	"""
	ws_name = "Invoicing"
	link_to = "Bank Statement Importer"
	card_label = "Banking"

	if not frappe.db.exists("Workspace", ws_name):
		return
	if not frappe.db.exists("DocType", link_to):
		return

	ws = frappe.get_doc("Workspace", ws_name)

	if any(l.type == "Link" and l.link_to == link_to for l in ws.links):
		return

	# Find the position of the "Banking" card break.
	banking_idx = None
	for i, link in enumerate(ws.links):
		if link.type == "Card Break" and (link.label or "").strip() == card_label:
			banking_idx = i
			break

	if banking_idx is None:
		# No Banking card break — bail out instead of appending in a random spot.
		print(f"BI: '{card_label}' Card Break not found on '{ws_name}' workspace, skipping link insert")
		return

	# Find the next Card Break — our link goes right before it (end of Banking
	# section). If Banking is the last card, append to the very end.
	next_card_idx = len(ws.links)
	for i in range(banking_idx + 1, len(ws.links)):
		if ws.links[i].type == "Card Break":
			next_card_idx = i
			break

	# Append a row (Frappe auto-assigns parent fields), then move it into place.
	ws.append("links", {
		"label": link_to,
		"link_to": link_to,
		"link_type": "DocType",
		"type": "Link",
		"onboard": 0,
		"is_query_report": 0,
		"hidden": 0,
	})
	new_row = ws.links.pop()
	ws.links.insert(next_card_idx, new_row)
	for i, l in enumerate(ws.links):
		l.idx = i + 1

	ws.flags.ignore_version = True
	ws.flags.ignore_permissions = True
	ws.save(ignore_permissions=True)
	frappe.db.commit()
	print(f"BI: added '{link_to}' link to '{card_label}' card on '{ws_name}' workspace")


def link_kb_bank_accounts_to_bi():
	"""For every Bank Account that appears in Kapital Bank Settings.account_mappings,
	set bank_integration_type='Kapital Bank Settings' / bank_integration='Kapital Bank Settings'
	if not already set. Idempotent."""
	if not frappe.db.exists("DocType", "Kapital Bank Account Mapping"):
		return

	rows = frappe.get_all(
		"Kapital Bank Account Mapping",
		filters={"parenttype": "Kapital Bank Settings"},
		fields=["bank_account"],
	)
	if not rows:
		return

	updated = 0
	for r in rows:
		if not r.bank_account:
			continue
		if not frappe.db.exists("Bank Account", r.bank_account):
			continue
		current = frappe.db.get_value(
			"Bank Account", r.bank_account, ["bank_integration_type", "bank_integration"], as_dict=True
		) or {}
		if current.get("bank_integration_type") and current.get("bank_integration"):
			continue

		frappe.db.set_value("Bank Account", r.bank_account, {
			"bank_integration_type": "Kapital Bank Settings",
			"bank_integration": "Kapital Bank Settings",
		}, update_modified=False)
		updated += 1

	if updated:
		frappe.db.commit()
		print(f"BI: linked {updated} kb-mapped Bank Account(s) to Kapital Bank Settings")


def _rename_to_readable(doctype, old_prefix, name_field):
	"""Rename `doctype` records still named `old_prefix`-#### to their `name_field`
	text (truncated to 140, -N on collision). Idempotent. Link refs update."""
	if not frappe.db.exists("DocType", doctype):
		return
	rows = frappe.get_all(
		doctype,
		filters={"name": ["like", f"{old_prefix}-%"]},
		fields=["name", name_field],
	)
	renamed = 0
	for r in rows:
		text = r.get(name_field)
		if not text:
			continue
		target = str(text)
		if len(target) > 140:
			target = target[:137] + "..."
		base = target
		counter = 1
		while target != r.name and frappe.db.exists(doctype, target):
			suffix = f"-{counter}"
			target = base[: 140 - len(suffix)] + suffix
			counter += 1
		if target == r.name:
			continue
		try:
			frappe.rename_doc(doctype, r.name, target, force=True, show_alert=False)
			renamed += 1
		except Exception as e:
			print(f"BI: failed to rename {doctype} {r.name}: {e}")
	if renamed:
		frappe.db.commit()
		print(f"BI: renamed {renamed} {doctype} record(s) to readable names")


def rename_bip_purposes():
	"""Migrate Bank Integration Purpose / Customer / Supplier records from the
	old BIP-/BIC-/BIS-#### ids to their text names (matching Kapital Bank)."""
	_rename_to_readable("Bank Integration Purpose", "BIP", "purpose_keyword")
	_rename_to_readable("Bank Integration Customer", "BIC", "customer_name")
	_rename_to_readable("Bank Integration Supplier", "BIS", "supplier_name")


_PRESET_FIELDS_TO_COPY = (
	"header_row",
	"amount_mode",
	"direction_debit_values",
	"direction_credit_values",
	"use_currency_from_file",
	"use_custom_date_format",
	"date_format",
	"sample_file",
)


def copy_excel_preset_into_bank_integration():
	"""Iteration: merging Bank Integration Excel Preset into Bank Integration.

	For each Bank Integration whose File Format is still empty (no column
	mappings, no format chosen), copy the format and column mappings from
	a Bank Integration Excel Preset. Strategy: pick the only user-created
	preset if there's exactly one (excluding the 'Generic Bank Statement'
	fixture); otherwise pick the fixture as a starting template.

	Idempotent: once a Bank Integration has any column mappings or an
	explicit amount_mode, it's left alone.
	"""
	if not frappe.db.exists("DocType", "Bank Statement Importer"):
		return
	if not frappe.db.exists("DocType", "Bank Integration Excel Preset"):
		return

	bi_names = frappe.get_all("Bank Statement Importer", pluck="name")
	if not bi_names:
		return

	preset_names = frappe.get_all(
		"Bank Integration Excel Preset",
		fields=["name"],
		order_by="modified desc",
		pluck="name",
	)
	if not preset_names:
		return

	non_fixture = [p for p in preset_names if p != "Generic Bank Statement"]
	chosen_preset_name = non_fixture[0] if len(non_fixture) == 1 else (
		non_fixture[0] if non_fixture else preset_names[0]
	)
	preset = frappe.get_doc("Bank Integration Excel Preset", chosen_preset_name)

	copied = 0
	for bi_name in bi_names:
		bi = frappe.get_doc("Bank Statement Importer", bi_name)
		# Skip if File Format already configured.
		if bi.column_mappings or (bi.amount_mode and bi.amount_mode != "Separate debit/credit columns"):
			continue
		if bi.column_mappings:
			continue
		for f in _PRESET_FIELDS_TO_COPY:
			value = preset.get(f)
			if value is None:
				continue
			bi.set(f, value)
		for row in preset.column_mappings or []:
			bi.append("column_mappings", {
				"excel_column": row.excel_column,
				"standard_field": row.standard_field,
				"notes": row.notes,
			})
		bi.flags.ignore_validate = True
		bi.flags.ignore_mandatory = True
		bi.save(ignore_permissions=True)
		copied += 1

	if copied:
		frappe.db.commit()
		print(f"BI: copied File Format from preset '{chosen_preset_name}' into {copied} Bank Integration(s)")
