# Sales Invoice multi tax-article — server-side foundation.
#
# Source of truth for the (possibly multiple) tax articles of an invoice line is
# the parent table `custom_item_tax_articles` (child DocType "Sales Invoice Tax
# Article"), whose rows are linked to an item row by `custom_si_row_key`.
#
# This validate hook:
#   1. guarantees every item row has a stable `custom_si_row_key` (so SQL joins
#      from `Sales Invoice Item` to `Sales Invoice Tax Article` are reliable),
#   2. drops ONLY orphaned article rows (whose parent_row matches no item row) —
#      the user's selection is otherwise kept regardless of tax template,
#   3. refreshes the `custom_tax_articles_display` text (the grid cell summary).
#
# It deliberately does NOT write the legacy single `tax_article` field: after
# Phase 2 the consumers (VAT Allocation, tax reports) JOIN the child table, so the
# single field is unused on Sales Invoice — and writing it fought vat_calculator.js
# (which clears it on refresh for non-0% lines), leaving the form perpetually dirty.

import frappe


def sync_item_tax_articles(doc, method=None):
    if doc.doctype != "Sales Invoice":
        return

    # 1) ensure each item row has a unique, stable row key (links it to its articles)
    seen = set()
    for item in doc.get("items", []):
        key = item.get("custom_si_row_key")
        if not key or key in seen:
            key = "r" + frappe.generate_hash(length=10)
            item.custom_si_row_key = key
        seen.add(key)

    # 2) keep every article row that points at a real item row; drop only orphans.
    #    NOTE: we intentionally do NOT drop by item_tax_template — the user's
    #    selection must survive saving even if the template is empty/non-0%.
    item_keys = {item.custom_si_row_key for item in doc.get("items", [])}
    rows = [
        r
        for r in (doc.get("custom_item_tax_articles") or [])
        if r.get("parent_row") in item_keys and r.get("tax_article")
    ]
    doc.custom_item_tax_articles = rows

    # 3) refresh the per-row "Tax Articles" display label
    by_row = {}
    for r in rows:
        by_row.setdefault(r.parent_row, []).append(r.tax_article)

    for item in doc.get("items", []):
        articles = by_row.get(item.custom_si_row_key, [])
        if hasattr(item, "custom_tax_articles_display"):
            item.custom_tax_articles_display = _display_label(len(articles))


def _display_label(n: int) -> str:
    """Short summary shown in the grid cell (avoids the Data field length limit)."""
    if n:
        return frappe._("{0} selected").format(n)
    return frappe._("Click to select")
