"""
create_balance_entries
Generates one ``BalanceMovement`` (type ENTRY) for every line item of a
processed import invoice, writing the initial inventory balance for each lot.

Design rules (from a24.balance_movement):
  1. NEVER update existing rows — only INSERT.
  2. Balance = SUM of movements. No cached balance columns.
  3. order_peps is set to the new movement's id (globally monotonic) via a
     post-flush assignment — SQLAlchemy fills autoincrement ids after flush.

This function is called AFTER all validations pass and BEFORE db.flush() at
the end of the import main_process, so all inserts are part of the same
transaction.
"""

from decimal import Decimal
from typing import List

from sqlalchemy.orm import Session

from api.v1.modules.a24.balance_movements.models import BalanceMovement, MovementType
from api.v1.modules.a76.invoices.models import InvoiceHeader
from api.v1.modules.a76.items.models import LineItem


def create_balance_entries(
    db: Session,
    invoice: InvoiceHeader,
    lines: List[LineItem],
) -> List[BalanceMovement]:
    """
    Inserts one ``BalanceMovement(type=ENTRY)`` for every import line item.

    Parameters
    ----------
    db      : active SQLAlchemy session (inside the process transaction)
    invoice : the import invoice that has just been validated and totalled
    lines   : all LineItem rows of the invoice

    Returns
    -------
    List of the newly created BalanceMovement objects (already added to the
    session, ids available after the next flush).

    Notes
    -----
    - ``order_peps`` is set equal to ``movement.id`` right after flush so that
      the PEPS index is globally monotonic — older imports always have a lower
      value and are consumed first on export.
    - Sub-items (fa_data.is_subitem = True) are skipped; only principal lines
      contribute to inventory.
    - Lines with quantity = 0 are skipped to keep the ledger clean.
    """
    movements: List[BalanceMovement] = []

    operation_date = (
        invoice.invoice_date.date()
        if hasattr(invoice.invoice_date, "date")
        else invoice.invoice_date
    )

    for line in lines:
        # Skip sub-items — they have no independent balance
        is_subitem = line.fa_data.is_subitem if line.fa_data else False
        if is_subitem:
            continue

        qty = (
            Decimal(str(line.quantity.quantity or 0))
            if line.quantity
            else Decimal(0)
        )
        if qty <= 0:
            continue

        value_me = (
            Decimal(str(line.financial.value_usd or 0))
            if line.financial
            else Decimal(0)
        )
        value_mn = (
            Decimal(str(line.financial.value_mxn or 0))
            if line.financial
            else Decimal(0)
        )
        net_weight = (
            Decimal(str(line.quantity.net_weight or 0))
            if line.quantity
            else Decimal(0)
        )

        movement = BalanceMovement(
            tenant_id=invoice.tenant_id,
            company_id=invoice.company_id,
            import_invoice_id=invoice.id,
            import_item_line_id=line.id,
            part_number_id=line.part_number_id,
            movement_type=MovementType.ENTRY,
            quantity=qty,
            value_me=value_me if value_me > 0 else None,
            value_mn=value_mn if value_mn > 0 else None,
            net_weight=net_weight if net_weight > 0 else None,
            source_invoice_id=None,
            source_item_line_id=None,
            order_peps=0,          # placeholder — set after flush (see below)
            operation_date=operation_date,
            notes=f"Entrada por factura de importación {invoice.invoice_number}",
        )
        db.add(movement)
        movements.append(movement)

    if movements:
        # Flush to get autoincrement ids, then set order_peps = id so that
        # the PEPS index is monotonic and requires no separate sequence.
        db.flush()
        for mov in movements:
            mov.order_peps = mov.id

    return movements
