"""
Cash Method (Kassa Metodu) — Payment Entry Hook

When a company uses Kassa metodu, VAT obligations and revenue are recognized
only when payment is received/made, not at invoice time.

This hook runs on Payment Entry submission and creates Journal Entries
to transfer deferred amounts:
  - 245.1 (ƏDV gözləmədə satış) → 521.3 (ƏDV к уплате)
  - 245.2 (ƏDV gözləmədə alış) → 226 (ƏDV к зачёту)
  - 542 (Отложенный доход) → 601 (Доход)
"""

import frappe
from frappe import _
from frappe.utils import flt


def _get_accounting_method(company):
	if not frappe.db.has_column("Company", "accounting_method"):
		return ""
	return frappe.db.get_value("Company", company, "accounting_method") or ""


def on_payment_entry_submit(doc, method):
	"""Hook: called when Payment Entry is submitted."""
	company = doc.company
	accounting_method = _get_accounting_method(company)

	if accounting_method != "Kassa metodu":
		return

	settings = frappe.get_single("Tax Period Closing Settings")
	deferred_vat_sales = settings.deferred_vat_sales_account
	deferred_vat_purchase = settings.deferred_vat_purchase_account
	deferred_revenue = settings.deferred_revenue_account
	vat_output = settings.vat_output_account
	vat_input = settings.vat_input_account

	if not deferred_vat_sales or not vat_output:
		return

	for ref in doc.references or []:
		if not ref.reference_doctype or not ref.reference_name:
			continue

		if ref.reference_doctype == "Sales Invoice":
			_process_sales_payment(
				doc, ref, deferred_vat_sales, vat_output,
				deferred_revenue, settings
			)
		elif ref.reference_doctype == "Purchase Invoice":
			_process_purchase_payment(
				doc, ref, deferred_vat_purchase, vat_input, settings
			)


def _process_sales_payment(payment, ref, deferred_vat_acc, vat_output_acc,
		deferred_revenue_acc, settings):
	"""Transfer deferred VAT and revenue for a sales payment."""
	si = frappe.get_doc("Sales Invoice", ref.reference_name)
	if not si or si.docstatus != 1:
		return

	# Calculate payment ratio
	total_invoice = flt(si.grand_total) or 1
	paid_amount = flt(ref.allocated_amount)
	ratio = paid_amount / total_invoice

	# VAT portion
	total_vat = flt(si.total_taxes_and_charges)
	vat_to_transfer = flt(total_vat * ratio, 2)

	# Revenue portion (net total)
	total_net = flt(si.net_total)
	revenue_to_transfer = flt(total_net * ratio, 2)

	entries = []

	# Transfer deferred VAT → actual VAT obligation
	if vat_to_transfer > 0 and deferred_vat_acc:
		entries.append({
			"debit_account": deferred_vat_acc,
			"credit_account": vat_output_acc,
			"amount": vat_to_transfer,
			"remark": (f"Kassa metodu: ƏDV tanınması — {ref.reference_name} "
				f"({ratio*100:.0f}% ödənildi). Payment: {payment.name}"),
		})

	# Transfer deferred revenue → actual revenue
	if revenue_to_transfer > 0 and deferred_revenue_acc:
		# Find the income account from the invoice
		income_account = None
		for item in si.items:
			if item.income_account:
				income_account = item.income_account
				break

		if income_account:
			entries.append({
				"debit_account": deferred_revenue_acc,
				"credit_account": income_account,
				"amount": revenue_to_transfer,
				"remark": (f"Kassa metodu: gəlir tanınması — {ref.reference_name} "
					f"({ratio*100:.0f}% ödənildi). Payment: {payment.name}"),
			})

	# Create Journal Entries
	for entry in entries:
		_create_transfer_je(payment, entry, settings)


def _process_purchase_payment(payment, ref, deferred_vat_acc, vat_input_acc, settings):
	"""Transfer deferred input VAT for a purchase payment."""
	pi = frappe.get_doc("Purchase Invoice", ref.reference_name)
	if not pi or pi.docstatus != 1:
		return

	total_invoice = flt(pi.grand_total) or 1
	paid_amount = flt(ref.allocated_amount)
	ratio = paid_amount / total_invoice

	total_vat = flt(pi.total_taxes_and_charges)
	vat_to_transfer = flt(total_vat * ratio, 2)

	if vat_to_transfer > 0 and deferred_vat_acc and vat_input_acc:
		_create_transfer_je(payment, {
			"debit_account": vat_input_acc,
			"credit_account": deferred_vat_acc,
			"amount": vat_to_transfer,
			"remark": (f"Kassa metodu: ƏDV əvəzləşdirmə — {ref.reference_name} "
				f"({ratio*100:.0f}% ödənildi). Payment: {payment.name}"),
		}, settings)


def _create_transfer_je(payment, entry, settings):
	"""Create a Journal Entry for cash method transfer."""
	je = frappe.new_doc("Journal Entry")
	je.company = payment.company
	je.posting_date = payment.posting_date
	je.voucher_type = "Journal Entry"
	je.user_remark = entry["remark"]

	cost_center = settings.default_cost_center or frappe.db.get_value(
		"Company", payment.company, "cost_center")

	je.append("accounts", {
		"account": entry["debit_account"],
		"debit_in_account_currency": entry["amount"],
		"cost_center": cost_center,
	})
	je.append("accounts", {
		"account": entry["credit_account"],
		"credit_in_account_currency": entry["amount"],
		"cost_center": cost_center,
	})

	je.insert(ignore_permissions=True)
	je.submit()


def on_journal_entry_submit(doc, method):
	"""Hook: when JE with Дт 226 / Кт 211 is submitted, auto-allocate via FIFO."""
	company = doc.company
	accounting_method = _get_accounting_method(company)

	if accounting_method != "Kassa metodu":
		return

	# Skip if this JE is itself a FIFO allocation
	if "FIFO" in (doc.user_remark or ""):
		return

	# Check if this JE has Дт 226 / Кт 211 (НДС от клиента)
	has_226_debit = False
	vat_amount = 0
	customer = None

	for row in doc.accounts:
		if "226" in (row.account or "") and flt(row.debit_in_account_currency) > 0:
			has_226_debit = True
			vat_amount += flt(row.debit_in_account_currency)
		if "211" in (row.account or "") and flt(row.credit_in_account_currency) > 0:
			customer = row.party

	if not has_226_debit or vat_amount <= 0:
		return

	# Auto FIFO allocation for this payment
	settings = frappe.get_single("Tax Period Closing Settings")
	deferred_vat = settings.deferred_vat_sales_account
	deferred_rev = settings.deferred_revenue_account
	vat_output = settings.vat_output_account

	if not deferred_vat or not deferred_rev or not vat_output:
		return

	# Find oldest unrecognized SI for this customer
	sis = frappe.db.sql("""
		SELECT si.name, si.grand_total, si.net_total, si.total_taxes_and_charges
		FROM `tabSales Invoice` si
		WHERE si.company=%s AND si.docstatus=1 AND si.customer=%s
		ORDER BY si.posting_date
	""", (company, customer), as_dict=True)

	cost_center = settings.default_cost_center or frappe.db.get_value(
		"Company", company, "cost_center")
	income_account = frappe.db.get_value("Account", {
		"company": company, "account_number": "601", "is_group": 0
	}, "name")

	remaining = vat_amount  # НДС amount = proxy for payment amount

	for si in sis:
		if remaining <= 0.01:
			break

		# Check how much already recognized
		recognized_vat = abs(flt(frappe.db.sql("""
			SELECT SUM(debit) FROM `tabGL Entry`
			WHERE account=%s AND is_cancelled=0
			AND against_voucher_type='Sales Invoice' AND against_voucher=%s
		""", (deferred_vat, si.name))[0][0] or 0))

		si_vat = flt(si.total_taxes_and_charges)
		unrecognized_vat = si_vat - recognized_vat
		if unrecognized_vat <= 0.01:
			continue

		allocate_vat = min(remaining, unrecognized_vat)
		ratio = allocate_vat / si_vat if si_vat else 0
		allocate_rev = flt(si.net_total * ratio, 2)

		# Create transfer JE
		transfer_je = frappe.new_doc("Journal Entry")
		transfer_je.company = company
		transfer_je.posting_date = doc.posting_date
		transfer_je.voucher_type = "Journal Entry"
		transfer_je.user_remark = (
			f"FIFO Kassa auto: {si.name} ({ratio*100:.0f}%). "
			f"Source JE: {doc.name}"
		)

		if allocate_vat > 0:
			transfer_je.append("accounts", {
				"account": deferred_vat, "debit_in_account_currency": allocate_vat,
				"cost_center": cost_center,
				"against_voucher_type": "Sales Invoice", "against_voucher": si.name,
			})
			transfer_je.append("accounts", {
				"account": vat_output, "credit_in_account_currency": allocate_vat,
				"cost_center": cost_center,
			})

		if allocate_rev > 0 and income_account:
			transfer_je.append("accounts", {
				"account": deferred_rev, "debit_in_account_currency": allocate_rev,
				"cost_center": cost_center,
				"against_voucher_type": "Sales Invoice", "against_voucher": si.name,
			})
			transfer_je.append("accounts", {
				"account": income_account, "credit_in_account_currency": allocate_rev,
				"cost_center": cost_center,
			})

		transfer_je.insert(ignore_permissions=True)
		transfer_je.submit()
		remaining -= allocate_vat


def on_payment_entry_cancel(doc, method):
	"""Hook: cancel related cash method JEs when Payment is cancelled."""
	company = doc.company
	accounting_method = _get_accounting_method(company)

	if accounting_method != "Kassa metodu":
		return

	# Find JEs created by this payment
	jes = frappe.get_all("Journal Entry", filters={
		"user_remark": ["like", f"%Payment: {doc.name}%"],
		"docstatus": 1,
	}, pluck="name")

	for je_name in jes:
		je = frappe.get_doc("Journal Entry", je_name)
		je.cancel()
