from importlib.util import module_from_spec, spec_from_file_location
from pathlib import Path
import sys

from app.work_center_action_policy import (
    effective_action_code,
    reconstructed_review_status,
)


def _ensure_real_sqlalchemy():
    module = sys.modules.get("sqlalchemy")
    if module is not None and not hasattr(module, "__path__"):
        for key in list(sys.modules):
            if key == "sqlalchemy" or key.startswith("sqlalchemy."):
                sys.modules.pop(key, None)


def _normalise(items):
    _ensure_real_sqlalchemy()
    from app.operations_service import _normalise_work_item_intent
    return _normalise_work_item_intent(items)


def _physical_status(sale, pickings, productions):
    _ensure_real_sqlalchemy()
    from app.odoo_service import _derive_physical_status
    return _derive_physical_status(sale, pickings, productions)


ROOT = Path(__file__).resolve().parents[1]


def _load_script():
    _ensure_real_sqlalchemy()
    path = ROOT / "scripts" / "apply_v132_operational_coherence.py"
    spec = spec_from_file_location("apply_v132_operational_coherence", path)
    module = module_from_spec(spec)
    assert spec and spec.loader
    sys.modules[spec.name] = module
    spec.loader.exec_module(module)
    return module


def test_title_sem_oportunidade_does_not_invent_association_blocker():
    item = {
        "action_code": "FOLLOW_UP_PAYMENT",
        "opportunity_title": "Orçamento Jasmin sem oportunidade · ORC.1",
        "opportunity_linking_status": "",
        "opportunity_metadata": {},
    }
    result = _normalise([item])[0]
    assert result["action_code"] == "FOLLOW_UP_PAYMENT"


def test_explicit_association_blocker_still_wins():
    item = {
        "action_code": "FOLLOW_UP_PAYMENT",
        "opportunity_linking_status": "ambiguous",
        "opportunity_metadata": {},
    }
    result = _normalise([item])[0]
    assert result["action_code"] == "ASSOCIATE_OPPORTUNITY"


def test_explicit_reconstructed_review_blocks_physical_validation():
    metadata = {
        "clientflow_record_mode": "reconstructed_invoice_review",
        "reconstructed_review_status": "required",
    }
    item = {
        "action_code": "VALIDATE_PHYSICAL_ORDER",
        "opportunity_metadata": metadata,
    }
    result = _normalise([item])[0]
    assert result["action_code"] == "REVIEW_RECONSTRUCTED_PROCESS"
    assert effective_action_code("VALIDATE_PHYSICAL_ORDER", metadata=metadata) == "REVIEW_RECONSTRUCTED_PROCESS"


def test_validated_reconstructed_review_does_not_reopen_from_title():
    metadata = {
        "clientflow_record_mode": "reconstructed_invoice_review",
        "reconstructed_review_status": "validated",
    }
    item = {
        "action_code": "SEND_INVOICE",
        "opportunity_title": "Processo reconstruído · Cliente",
        "opportunity_metadata": metadata,
    }
    result = _normalise([item])[0]
    assert result["action_code"] == "SEND_INVOICE"
    assert reconstructed_review_status(metadata) == "validated"


def test_board_prefers_pending_task_and_explicit_review():
    source = (ROOT / "app" / "admin_ui" / "pages" / "opportunities.py").read_text(encoding="utf-8")
    function = source[source.index("def _opportunity_card_next_action"):source.index("def _is_noise_opportunity")]
    assert function.index("reconstructed_review_required(metadata)") < function.index("central = _central_next_action_for_card")
    assert function.index("pending_primary_action_code") < function.index("central = _central_next_action_for_card")
    assert 'return "Validar processo reconstruído"' in function


def test_odoo_assigned_is_reserved_not_ready_to_ship():
    result = _physical_status(
        {"state": "sale"},
        [{"name": "WH/OUT/1", "state": "assigned", "picking_type_id": [2, "Delivery Orders"]}],
        [],
    )
    assert result["physical_status"] == "picking_assigned"
    assert result["stage"] == "ORDER_PREPARATION"
    assert result["ready_to_ship"] is False
    assert result["picking_reserved"] is True


def test_migration_plan_rewinds_assigned_and_requires_explicit_review():
    module = _load_script()
    opportunities = [{
        "id": "opp-1",
        "title": "Fwd cliente",
        "customer_name": "NOLTIA SYSTEM, LDA",
        "fiscal_name": "NOLTIA SYSTEM, LDA",
        "stage": "SHIPMENT_CREATED",
        "last_action_code": "VALIDATE_PHYSICAL_ORDER",
        "metadata": {"clientflow_record_mode": "reconstructed_invoice_review"},
    }]
    links = [{
        "opportunity_id": "opp-1", "system": "odoo", "external_type": "physical_status",
        "status": "picking_assigned", "payload": {"physical_status": "picking_assigned", "pickings": [{"state": "assigned"}]},
    }]
    tasks = [{
        "id": "task-1", "opportunity_id": "opp-1", "action_code": "VALIDATE_PHYSICAL_ORDER",
        "status": "pending", "metadata": {},
    }]
    plans = module._plan_opportunities(opportunities, links, tasks, [])
    assert len(plans) == 1
    plan = plans[0]
    assert plan.safe is True
    assert plan.target_stage == "ORDER_PREPARATION"
    assert plan.reconstructed_after == "required"
    assert plan.task_operation == "convert_sensitive_to_review"


def test_completed_review_is_persisted_as_validated_not_reopened():
    module = _load_script()
    opportunities = [{
        "id": "opp-2", "title": "Processo reconstruído", "customer_name": "RICARDO",
        "fiscal_name": "RICARDO", "stage": "PAYMENT_CONFIRMED", "last_action_code": "SEND_INVOICE",
        "metadata": {"clientflow_record_mode": "reconstructed_invoice_review", "reconstructed_review_required": True},
    }]
    tasks = [
        {"id": "review-done", "opportunity_id": "opp-2", "action_code": "REVIEW_RECONSTRUCTED_PROCESS", "status": "done", "metadata": {}},
        {"id": "invoice", "opportunity_id": "opp-2", "action_code": "SEND_INVOICE", "status": "pending", "metadata": {}},
    ]
    plans = module._plan_opportunities(opportunities, [], tasks, [])
    assert len(plans) == 1
    assert plans[0].reconstructed_after == "validated"
    assert plans[0].task_operation == "none"


def test_stale_candidate_requires_identity_unless_name_or_nif_matches():
    module = _load_script()
    items = [
        {"id": "i1", "external_id": "318", "document_number": "S00318", "customer_name": "DUNAS INVENCÍVEIS, LDA", "customer_tax_id": "", "payload": {}},
        {"id": "i2", "external_id": "323", "document_number": "S00323", "customer_name": "BBKW, LDA", "customer_tax_id": "", "payload": {}},
    ]
    links = [
        {"opportunity_id": "o1", "external_id": "318", "external_name": "S00318"},
        {"opportunity_id": "o2", "external_id": None, "external_name": "S00323"},
    ]
    opportunities = {
        "o1": {"fiscal_name": "DUNAS INVENCÍVEIS, UNIPESSOAL, LDA", "customer_name": "", "title": "", "fiscal_tax_id": ""},
        "o2": {"fiscal_name": "", "customer_name": "", "title": "", "fiscal_tax_id": ""},
    }
    plans = module._plan_candidates(items, links, opportunities, allow_unknown_identity=False)
    by_ref = {plan.reference: plan for plan in plans}
    assert by_ref["S00318"].safe is True
    assert by_ref["S00323"].safe is False
    assert by_ref["S00323"].reason == "identity_unknown_requires_review"


def test_reconciliation_no_longer_creates_validation_from_delivery_ready():
    source = (ROOT / "app" / "reconciliation_service.py").read_text(encoding="utf-8")
    assert 'if fulfilment.get("delivery_done"):' in source
    assert 'if fulfilment.get("delivery_done") or fulfilment.get("delivery_ready")' not in source
    assert "DELETE FROM operation_links" in source


def test_review_action_is_catalogued_and_completion_persists_validation():
    catalog = (ROOT / "app" / "action_catalog.py").read_text(encoding="utf-8")
    service = (ROOT / "app" / "opportunity_service.py").read_text(encoding="utf-8")
    assert '"REVIEW_RECONSTRUCTED_PROCESS": {' in catalog
    assert 'if action_code == "REVIEW_RECONSTRUCTED_PROCESS":' in service
    assert 'reconstructed_process_review_validated' in service
