import frappe
import json
from frappe.utils import flt


def calculate_tax_free_amounts(doc, method=None):
    """
    Calculate tax free amounts for Sales Invoice
    Called after calculate_taxes_and_totals
    """
    if doc.doctype != "Sales Invoice":
        return
    
    # Clear existing tax_free_amount values
    for tax in doc.get("taxes", []):
        if hasattr(tax, 'tax_free_amount'):
            tax.tax_free_amount = 0.0
    
    # Calculate tax free amounts
    for item in doc.get("items", []):
        if not item.get("item_code"):
            continue
            
        # Try to get tax template from item row first
        item_tax_template = item.get("item_tax_template")
        item_tax_rate = item.get("item_tax_rate")
        
        # If no tax info in item row, get from Item master
        if not item_tax_template and not item_tax_rate:
            try:
                item_doc = frappe.get_doc("Item", item.item_code)
                item_tax_template = item_doc.get("item_tax_template")
            except Exception:
                continue
        
        # Process item_tax_rate (JSON format)
        if item_tax_rate:
            try:
                if isinstance(item_tax_rate, str):
                    tax_rates = json.loads(item_tax_rate)
                else:
                    tax_rates = item_tax_rate
                    
                for account_head, rate in tax_rates.items():
                    if flt(rate) == 0.0:
                        # Find corresponding tax in sales invoice
                        for doc_tax in doc.get("taxes", []):
                            if doc_tax.account_head == account_head:
                                if hasattr(doc_tax, 'tax_free_amount'):
                                    doc_tax.tax_free_amount = flt(doc_tax.tax_free_amount) + flt(item.net_amount)
                                break
            except Exception:
                pass
        
        # Process item_tax_template
        elif item_tax_template:
            try:
                tax_template = frappe.get_doc("Item Tax Template", item_tax_template)
                
                for template_tax in tax_template.get("taxes", []):
                    if flt(template_tax.tax_rate) == 0.0:
                        # Find corresponding tax in sales invoice
                        for doc_tax in doc.get("taxes", []):
                            if doc_tax.account_head == template_tax.tax_type:
                                if hasattr(doc_tax, 'tax_free_amount'):
                                    doc_tax.tax_free_amount = flt(doc_tax.tax_free_amount) + flt(item.net_amount)
                                break
            except Exception:
                pass


@frappe.whitelist()
def recalculate_tax_free_amounts(doc):
    """
    API method to recalculate tax free amounts
    Called from client side when items change
    """
    if isinstance(doc, str):
        doc = frappe.parse_json(doc)
    
    # Convert to document object if it's a dict
    if isinstance(doc, dict):
        sales_invoice = frappe.get_doc(doc)
    else:
        sales_invoice = doc
    
    # Calculate tax free amounts
    calculate_tax_free_amounts(sales_invoice)
    
    # Return updated taxes
    taxes_data = []
    for tax in sales_invoice.get("taxes", []):
        tax_dict = tax.as_dict() if hasattr(tax, 'as_dict') else dict(tax)
        taxes_data.append(tax_dict)
        
    return taxes_data


@frappe.whitelist()
def sync_vat_to_taxes(doc):
    """
    Синхронизирует фактические VAT amounts из items в taxes таблицу
    Вызывается из клиентского JavaScript
    """
    if isinstance(doc, str):
        doc = frappe.parse_json(doc)

    # Словарь для агрегации VAT amounts по account_head
    vat_aggregates = {}

    # Агрегируем vat_amount из items
    for item in doc.get("items", []):
        if not item.get("item_code"):
            continue

        # Округляем до 2 знаков при чтении
        vat_amount = flt(item.get("vat_amount", 0), 2)
        if vat_amount <= 0:
            continue

        item_tax_template = item.get("item_tax_template")
        if not item_tax_template:
            continue

        # Получить account_head из налогового шаблона
        try:
            tax_template = frappe.get_doc("Item Tax Template", item_tax_template)
            if tax_template.taxes and len(tax_template.taxes) > 0:
                account_head = tax_template.taxes[0].tax_type

                if account_head not in vat_aggregates:
                    vat_aggregates[account_head] = 0.0
                vat_aggregates[account_head] += vat_amount
        except Exception:
            continue

    # Обновляем taxes таблицу
    updated_taxes = []
    for tax in doc.get("taxes", []):
        if tax.get("account_head") in vat_aggregates:
            # Округляем итоговую сумму до 2 знаков
            tax["tax_amount"] = flt(vat_aggregates[tax["account_head"]], 2)
            tax["base_tax_amount"] = flt(vat_aggregates[tax["account_head"]], 2)
        updated_taxes.append(tax)

    return updated_taxes


def sync_actual_vat_amounts(doc, method=None):
    """
    Перезаписывает tax_amount в taxes таблице фактическими суммами НДС из items.
    Вызывается после стандартного calculate_taxes_and_totals.
    """
    if doc.doctype not in ["Sales Invoice", "Sales Order"]:
        return

    # Словарь для агрегации сумм НДС по account_head
    vat_aggregates = {}

    # Агрегировать фактические суммы НДС из items
    for item in doc.get("items", []):
        if not item.get("item_code"):
            continue

        # Получить фактическую сумму НДС из строки товара
        vat_amount = flt(item.get("vat_amount", 0), 2)

        if vat_amount <= 0:
            continue

        # Получить налоговый шаблон товара
        item_tax_template = item.get("item_tax_template")

        if not item_tax_template:
            # Если нет шаблона в строке, проверить Item master
            try:
                item_doc = frappe.get_doc("Item", item.item_code)
                item_tax_template = item_doc.get("item_tax_template")
            except Exception:
                continue

        if not item_tax_template:
            continue

        # Получить account_head из налогового шаблона
        try:
            tax_template = frappe.get_doc("Item Tax Template", item_tax_template)

            # Взять первый tax_type (account_head) из шаблона
            if tax_template.taxes and len(tax_template.taxes) > 0:
                account_head = tax_template.taxes[0].tax_type

                # Агрегировать сумму НДС с округлением
                if account_head not in vat_aggregates:
                    vat_aggregates[account_head] = 0.0
                vat_aggregates[account_head] += vat_amount
        except Exception:
            continue

    # ПЕРЕЗАПИСАТЬ tax_amount в taxes таблице агрегированными суммами
    for tax in doc.get("taxes", []):
        account_head = tax.account_head
        if account_head in vat_aggregates:
            # Заменить стандартный расчет ERPNext нашей фактической суммой
            # Округляем до 2 знаков
            tax.tax_amount = flt(vat_aggregates[account_head], 2)
            # Также обновить base_tax_amount для мультивалютных документов
            tax.base_tax_amount = flt(vat_aggregates[account_head], 2)