"""v4.9.20: one fiscal customer can have multiple simultaneous orders.

Customer identity (NIF/fiscal name) must not be confused with commercial
operation identity.  Two Odoo sale orders for the same company should be shown
as two process candidates, not collapsed into one card.
"""

import sys
import types

if "sqlalchemy" not in sys.modules:
    sqlalchemy = types.ModuleType("sqlalchemy")
    sqlalchemy.text = lambda sql: sql
    sys.modules["sqlalchemy"] = sqlalchemy

if "app.db" not in sys.modules:
    app_db = types.ModuleType("app.db")
    app_db.engine = object()
    sys.modules["app.db"] = app_db

if "app.action_catalog" not in sys.modules:
    action_catalog = types.ModuleType("app.action_catalog")
    action_catalog.get_action_config = lambda code: {"route": "rever", "action": code, "action_required": True, "safe_to_post": False}
    sys.modules["app.action_catalog"] = action_catalog

from app import reconciliation_service as svc


def _odoo_sale(id_, number, amount, product):
    return {
        "id": id_,
        "source_system": "odoo",
        "external_type": "odoo_sale_order",
        "title": f"Venda Odoo sem oportunidade · {number}",
        "customer_name": "ACZCO BRAGA ENERGY, LDA",
        "customer_tax_id": "517249200",
        "document_number": number,
        "document_date": "2026-06-05",
        "amount": amount,
        "currency": "EUR",
        "payload": {
            "record": {
                "name": number,
                "invoice_status": "to invoice",
                "fulfilment": {
                    "invoice_pending": True,
                    "lines": [{"id": f"line-{number}", "product_name": product, "qty_ordered": 1, "price_total": amount}],
                },
            }
        },
        "operation_suggestions": [],
    }


def test_same_company_two_odoo_orders_become_two_process_candidates(monkeypatch):
    monkeypatch.setattr(
        svc,
        "list_reconciliation_items",
        lambda *, status, limit, days: [
            _odoo_sale("sale-279", "S00279", "638.60", "Wallbox 7.4KW"),
            _odoo_sale("sale-280", "S00280", "190.00", "Cabo"),
        ],
    )

    candidates = svc.list_reconciliation_process_candidates(status="open", days=7, limit=10)

    assert len(candidates) == 2
    process_keys = {candidate["process_key"] for candidate in candidates}
    assert any("S00279" in key for key in process_keys)
    assert any("S00280" in key for key in process_keys)
    assert {tuple(candidate["item_ids"]) for candidate in candidates} == {("sale-279",), ("sale-280",)}
    assert all(candidate["match_key"] == "nif" for candidate in candidates)
    assert all(candidate["suggested_action"] == "SEND_INVOICE" for candidate in candidates)


def test_loose_quote_assigns_to_matching_order_by_amount(monkeypatch):
    monkeypatch.setattr(
        svc,
        "list_reconciliation_items",
        lambda *, status, limit, days: [
            {
                "id": "quote-279",
                "source_system": "jasmin",
                "external_type": "jasmin_quotation",
                "title": "Orçamento Jasmin sem oportunidade · ORC.ORC2026.154",
                "customer_name": "ACZCO BRAGA ENERGY, LDA",
                "customer_tax_id": "517249200",
                "document_number": "ORC.ORC2026.154",
                "document_date": "2026-06-05",
                "amount": "638.60",
                "currency": "EUR",
                "operation_suggestions": [],
            },
            _odoo_sale("sale-279", "S00279", "638.60", "Wallbox 7.4KW"),
            _odoo_sale("sale-280", "S00280", "190.00", "Cabo"),
        ],
    )

    candidates = svc.list_reconciliation_process_candidates(status="open", days=7, limit=10)

    assert len(candidates) == 2
    grouped = {candidate["operation_key"]: set(candidate["item_ids"]) for candidate in candidates}
    assert grouped["odoo_sale_order:S00279"] == {"quote-279", "sale-279"}
    assert grouped["odoo_sale_order:S00280"] == {"sale-280"}
