#!/usr/bin/env python3
"""Read-only local UDF lineage fixture. No SAP, database, HTTP or ERP writes."""
from dataclasses import dataclass, replace
from hashlib import sha256
import json


@dataclass(frozen=True)
class Context:
    installation: str
    company: str
    entity_set: str
    record_key: str
    field: str
    target: str


def diagnose(expected: Context, observed: Context, declared: set[str], raw: dict, decoded: dict, mapped: dict) -> str:
    """Inspect supplied modern-metadata fixture and a non-empty string contract."""
    if observed.installation != expected.installation or observed.company != expected.company:
        return "wrong_source_context"
    if observed.entity_set != expected.entity_set:
        return "wrong_entity"
    if observed.record_key != expected.record_key:
        return "wrong_record_context"
    if observed.field != expected.field or observed.target != expected.target:
        return "wrong_mapping_contract"
    if not expected.field.startswith("U_"):
        return "not_udf_property"
    if expected.field not in declared:
        return "not_declared_in_supplied_metadata"
    if raw.get("CardCode") != expected.record_key:
        return "wrong_source_record"
    if expected.field not in raw:
        return "absent_from_source_response"
    value = raw[expected.field]
    if value is None:
        return "source_null"
    if not isinstance(value, str):
        return "source_type_mismatch"
    if value == "":
        return "source_empty"
    if decoded.get("CardCode") != expected.record_key:
        return "wrong_decoded_record"
    if expected.field not in decoded:
        return "dropped_by_decoder"
    if type(decoded[expected.field]) is not str or decoded[expected.field] != value:
        return "changed_by_decoder"
    if mapped.get("customer_reference") != expected.record_key:
        return "wrong_target_record"
    if expected.target not in mapped:
        return "missing_target_mapping"
    if type(mapped[expected.target]) is not str or mapped[expected.target] != value:
        return "changed_by_mapping"
    return "locally_preserved"


def receipt(context: Context, raw: dict) -> str:
    """Local comparison receipt, not SAP idempotency or authorization."""
    value = [context.installation, context.company, context.entity_set, context.record_key, context.field, context.target, raw]
    return sha256(json.dumps(value, sort_keys=True, ensure_ascii=False, separators=(",", ":")).encode()).hexdigest()


def run() -> int:
    count = 0
    def check(condition: bool, label: str) -> None:
        nonlocal count
        if not condition:
            raise AssertionError(label)
        count += 1

    c = Context("sap-fixture-fr", "SOCIETE_A", "BusinessPartners", "C-FICTIF-42", "U_ExportZone", "preparation_zone")
    declared = {"CardCode", "CardName", "U_ExportZone"}
    raw = {"CardCode": "C-FICTIF-42", "U_ExportZone": "A2"}
    decoded = dict(raw)
    mapped = {"customer_reference": "C-FICTIF-42", "preparation_zone": "A2"}
    inspect = lambda observed=c, fields=declared, source=raw, dto=decoded, target=mapped: diagnose(c, observed, fields, source, dto, target)
    check(inspect() == "locally_preserved", "field preserved across supplied stages")
    check(inspect(observed=replace(c, company="SOCIETE_B")) == "wrong_source_context", "wrong company")
    check(inspect(observed=replace(c, installation="sap-fixture-recette")) == "wrong_source_context", "wrong installation")
    check(inspect(observed=replace(c, entity_set="Orders")) == "wrong_entity", "UI field owner not another entity")
    check(inspect(observed=replace(c, record_key="C-FICTIF-43")) == "wrong_record_context", "wrong requested partner")
    check(inspect(source={**raw, "CardCode": "C-FICTIF-43"}) == "wrong_source_record", "wrong raw partner")
    check(inspect(dto={**decoded, "CardCode": "C-FICTIF-43"}) == "wrong_decoded_record", "decoder changed partner identity")
    check(inspect(target={**mapped, "customer_reference": "C-FICTIF-43"}) == "wrong_target_record", "mapping targets another partner")
    check(receipt(c, raw) != receipt(replace(c, record_key="C-FICTIF-43"), raw), "record identity separates receipt")
    check(inspect(observed=replace(c, field="U_OtherZone")) == "wrong_mapping_contract", "wrong technical field")
    check(inspect(observed=replace(c, target="delivery_zone")) == "wrong_mapping_contract", "wrong target contract")
    bad = replace(c, field="Zone de préparation")
    check(diagnose(bad, bad, {bad.field}, {bad.field: "A2"}, {bad.field: "A2"}, mapped) == "not_udf_property", "UI label is not UDF property")
    check(inspect(fields={"CardCode"}) == "not_declared_in_supplied_metadata", "supplied modern metadata lacks property")
    check(inspect(source={"CardCode": "C-FICTIF-42"}) == "absent_from_source_response", "projection omitted property")
    check(inspect(source={**raw, "U_ExportZone": None}) == "source_null", "explicit null differs from missing")
    check(inspect(source={**raw, "U_ExportZone": ""}) == "source_empty", "empty differs from null")
    check(inspect(source={**raw, "U_ExportZone": 2}) == "source_type_mismatch", "numeric value violates fixture string contract")
    check(inspect(source={**raw, "U_ExportZone": False}) == "source_type_mismatch", "boolean is not string")
    check(inspect(source={**raw, "U_ExportZone": []}) == "source_type_mismatch", "array is not string")
    check(inspect(dto={"CardCode": "C-FICTIF-42"}) == "dropped_by_decoder", "DTO allowlist dropped custom property")
    check(inspect(dto={**decoded, "U_ExportZone": None}) == "changed_by_decoder", "decoder inserted null")
    check(inspect(dto={**decoded, "U_ExportZone": "a2"}) == "changed_by_decoder", "case normalization changes contract")
    check(inspect(dto={**decoded, "U_ExportZone": "A2 "}) == "changed_by_decoder", "silent whitespace transform detected")
    check(inspect(dto={**decoded, "U_ExportZone": 2}) == "changed_by_decoder", "decoder type changed")
    check(inspect(target={"customer_reference": "C-FICTIF-42"}) == "missing_target_mapping", "mapping omission")
    check(inspect(target={**mapped, "preparation_zone": None}) == "changed_by_mapping", "mapping null differs")
    check(inspect(target={**mapped, "preparation_zone": "B7"}) == "changed_by_mapping", "wrong target value")
    check(inspect(target={**mapped, "preparation_zone": 2}) == "changed_by_mapping", "mapping type differs")
    check(inspect(source={**raw, "U_Extra": "unused"}) == "locally_preserved", "unrelated property does not alter selected lineage")
    check(receipt(c, raw) != receipt(replace(c, company="SOCIETE_B"), raw), "company separates local receipt")
    check(receipt(c, raw) != receipt(replace(c, installation="sap-fixture-recette"), raw), "installation separates receipt")
    check(receipt(c, raw) != receipt(replace(c, entity_set="Orders"), raw), "entity separates receipt")
    check(receipt(c, raw) != receipt(c, {**raw, "U_ExportZone": "B7"}), "source revision differs")
    check(receipt(c, raw) == receipt(c, dict(reversed(list(raw.items())))), "JSON key order does not alter local receipt")
    check(raw == {"CardCode": "C-FICTIF-42", "U_ExportZone": "A2"}, "source fixture not modified")
    check(mapped == {"customer_reference": "C-FICTIF-42", "preparation_zone": "A2"}, "target fixture not modified")
    print(f"{count} local checks passed. Native SAP reads: 0; HTTP calls: 0; ERP writes: 0.")
    return count


if __name__ == "__main__":
    run()
