#!/usr/bin/env python
"""schemas_b.py — batch B: analysis chain (8 schemas).

expression_scenario, gem_card_raw, metabolic_model_ref, host_model_binding,
gpr_proof, coupling_profile, consequence_run, tier_decision
"""
from schema_helpers import arr, aref, check, dec, obj, sha, schema, sref, ts_

SCHEMAS = {}

SCHEMAS["expression_scenario"] = schema(
    "expression_scenario",
    "expression_scenario@1 (no absolute-expression claims outside domain)",
    {
        "type": "object",
        "additionalProperties": False,
        "required": ["artifact_type", "circuit_design", "host_profile", "method", "results", "domain_check", "ranking_set_id", "comparison_scope", "metric_definition", "higher_is"],
        "properties": {
            "artifact_type": {"const": "expression_scenario@1"},
            "circuit_design": aref(),
            "host_profile": aref(),
            "method": {"enum": ["evidence_lookup", "ostir_proxy", "user_parameters"]},
            "results": arr("set", obj(
                {
                    "element": {"type": "string", "minLength": 1, "maxLength": 256},
                    "metric": {"type": "string", "minLength": 1, "maxLength": 256},
                    "value_or_rank": obj(
                        {
                            "kind": {"enum": ["value", "rank"]},
                            "value": dec(),
                            "rank": {"type": "integer", "minimum": 1},
                        },
                        ["kind"],
                    ),
                    "unit": {"type": "string", "maxLength": 64},
                    "conditions": {"type": "string", "maxLength": 256},
                    "evidence_level": {"enum": ["E0", "E1", "E2", "E3"]},
                },
                ["element", "metric", "value_or_rank"],
            )),
            "domain_check": {"enum": ["in_domain", "out_of_domain", "unknown"]},
            "assumptions": arr("set", {"type": "string", "minLength": 1, "maxLength": 2048}),
            "ranking_set_id": {"type": "string", "minLength": 1, "maxLength": 128},
            "comparison_scope": {"type": "string", "minLength": 1, "maxLength": 256},
            "metric_definition": {"type": "string", "minLength": 1, "maxLength": 512},
            "higher_is": {"enum": ["high", "low"]},
            "sequence_context_ref": aref(),
            "model_or_dataset_ref": aref(),
            "parameter_hash": sha(),
            "uncertainty": {"type": "string", "maxLength": 2048},
            "candidate_universe_ref": aref(),
            "rank_algorithm": obj(
                {
                    "id": {"type": "string", "minLength": 1, "maxLength": 128},
                    "version": {"type": "string", "minLength": 1, "maxLength": 64},
                    "params": {"type": "object", "additionalProperties": True},
                },
                ["id", "version"],
            ),
            "tie_null_policy": {"type": "string", "maxLength": 512},
            "raw_metric_artifact_ref": aref(),
            "filter_records": arr("set", obj(
                {
                    "filter_id": {"type": "string", "minLength": 1, "maxLength": 128},
                    "detail": {"type": "string", "maxLength": 1024},
                },
                ["filter_id"],
            )),
        },
    },
)

SCHEMAS["gem_card_raw"] = schema(
    "gem_card_raw",
    "gem_card_raw@1 (frozen raw card bytes; no runtime augmentation)",
    {
        "type": "object",
        "additionalProperties": False,
        "required": ["artifact_type", "card_schema", "raw_sha256", "raw_bytes_ref"],
        "properties": {
            "artifact_type": {"const": "gem_card_raw@1"},
            "card_schema": {"enum": ["v2", "v3", "legacy_missing_schema", "unsupported_major"]},
            "raw_sha256": sha(),
            "raw_bytes_ref": aref(),
            "original_filename": {"type": "string", "maxLength": 512},
        },
    },
)

SCHEMAS["metabolic_model_ref"] = schema(
    "metabolic_model_ref",
    "metabolic_model_ref@1 (regenerated by Genie; independent of gem card open fields)",
    {
        "type": "object",
        "additionalProperties": False,
        "required": ["artifact_type", "sbml_ref", "card", "model_id", "genome_link", "gpr", "objective", "baseline"],
        "properties": {
            "artifact_type": {"const": "metabolic_model_ref@1"},
            "sbml_ref": aref(),
            "card": obj(
                {
                    "card_schema": {"enum": ["v2", "v3", "legacy_missing_schema", "unsupported_major"]},
                    "card_ref": aref(),
                },
                ["card_schema"],
            ),
            "model_id": {"type": "string", "minLength": 1, "maxLength": 256},
            "genome_link": obj(
                {
                    "assembly": {"type": "string", "maxLength": 256},
                    "strain": {"type": "string", "maxLength": 256},
                    "genome_sha256": sha(),
                    "match_status": {"enum": ["exact", "evidence_missing", "conflict", "unresolved"]},
                },
                ["match_status"],
            ),
            "gpr": obj(
                {
                    "coverage_pct": {"type": "number", "minimum": 0, "maximum": 100},
                    "namespace": {"type": "string", "minLength": 1, "maxLength": 128},
                    "crosswalk_status": {"enum": ["exact", "versioned_alias", "ambiguous", "unmapped"]},
                },
                ["coverage_pct", "namespace", "crosswalk_status"],
            ),
            "medium_ref": aref(),
            "objective": {"type": "string", "minLength": 1, "maxLength": 256},
            "validation_claim": {"type": "string", "maxLength": 4096},
            "baseline": obj(
                {
                    "feasible": {"type": "boolean"},
                    "growth": dec(),
                    "solver": obj(
                        {
                            "id": {"type": "string", "minLength": 1, "maxLength": 64},
                            "version": {"type": "string", "minLength": 1, "maxLength": 64},
                        },
                        ["id", "version"],
                    ),
                },
                ["feasible", "solver"],
            ),
        },
    },
)

SCHEMAS["host_model_binding"] = schema(
    "host_model_binding",
    "host_model_binding@1 (only exact enters reference quantitative use)",
    {
        "type": "object",
        "additionalProperties": False,
        "required": ["artifact_type", "genome_sha256", "model_sbml_sha256", "binding_method", "evidence_source", "match_result"],
        "properties": {
            "artifact_type": {"const": "host_model_binding@1"},
            "genome_sha256": sha(),
            "model_sbml_sha256": sha(),
            "binding_method": obj(
                {
                    "id": {"type": "string", "minLength": 1, "maxLength": 128},
                    "version": {"type": "string", "minLength": 1, "maxLength": 64},
                },
                ["id", "version"],
            ),
            "evidence_source": {"type": "string", "minLength": 1, "maxLength": 1024},
            "match_result": {"enum": ["exact", "evidence_missing", "conflict", "unresolved"]},
        },
    },
)

SCHEMAS["gpr_proof"] = schema(
    "gpr_proof",
    "gpr_proof@1",
    {
        "type": "object",
        "additionalProperties": False,
        "required": ["artifact_type", "canonical_gpr_ast", "ast_hash", "source_gene_ids", "gem_gene_ids", "namespace", "reaction_id", "mapping_path"],
        "properties": {
            "artifact_type": {"const": "gpr_proof@1"},
            "canonical_gpr_ast": {"type": "string", "minLength": 1, "maxLength": 65536},
            "ast_hash": sha(),
            "source_gene_ids": arr("set", {"type": "string", "minLength": 1, "maxLength": 256}),
            "gem_gene_ids": arr("set", {"type": "string", "minLength": 1, "maxLength": 256}),
            "namespace": {"type": "string", "minLength": 1, "maxLength": 128},
            "reaction_id": {"type": "string", "minLength": 1, "maxLength": 256},
            "mapping_path": arr("seq", {"type": "string", "minLength": 1, "maxLength": 512}),
        },
    },
)

_RULE = {
    "type": "object",
    "additionalProperties": False,
    "required": ["rule_id", "model_ref", "host_profile", "host_model_binding_ref", "gpr_proof_ref", "condition_card_ref", "source_gene", "reaction_id", "reaction_direction", "operation", "baseline_bound", "derived_bound", "unit", "mapping_function", "condition_hash", "input_kind", "evidence_refs", "assumption_refs", "confidence"],
    "properties": {
        "rule_id": {"type": "string", "minLength": 1, "maxLength": 128},
        "model_ref": aref(),
        "host_profile": aref(),
        "host_model_binding_ref": aref(),
        "gpr_proof_ref": aref(),
        "condition_card_ref": aref(),
        "source_gene": obj(
            {
                "namespace": {"type": "string", "minLength": 1, "maxLength": 128},
                "id": {"type": "string", "minLength": 1, "maxLength": 256},
            },
            ["namespace", "id"],
        ),
        "reaction_id": {"type": "string", "minLength": 1, "maxLength": 256},
        "reaction_direction": {"enum": ["forward", "reverse", "both"]},
        "operation": {"enum": ["set_upper_bound", "set_lower_bound", "scale_bound"]},
        "baseline_bound": dec(),
        "derived_bound": dec(),
        "unit": {"type": "string", "minLength": 1, "maxLength": 64},
        "mapping_function": obj(
            {
                "id": {"type": "string", "minLength": 1, "maxLength": 128},
                "version": {"type": "string", "minLength": 1, "maxLength": 64},
                "parameters": {"type": "object", "additionalProperties": True},
            },
            ["id", "version", "parameters"],
        ),
        "condition_hash": sha(),
        "input_kind": {"enum": ["user_explicit_assumption", "measured_expression", "literature_calibration", "sequence_proxy", "manual_override"]},
        "evidence_refs": arr("set", sha()),
        "assumption_refs": arr("set", sha()),
        "confidence": {"enum": ["high", "medium", "low"]},
    },
    "allOf": [
        {
            "if": {"type": "object", "properties": {"input_kind": {"const": "manual_override"}}},
            "then": {
                "type": "object",
                "required": ["assumption_refs"],
                "properties": {"assumption_refs": {"type": "array", "minItems": 1}},
            },
        },
    ],
}

SCHEMAS["coupling_profile"] = schema(
    "coupling_profile",
    "coupling_profile@1 (the only authorized cross-layer entry)",
    {
        "type": "object",
        "additionalProperties": False,
        "required": ["artifact_type", "mode", "rules"],
        "properties": {
            "artifact_type": {"const": "coupling_profile@1"},
            "mode": {"enum": ["qualitative_direction", "user_calibrated_bound", "evidence_calibrated_bound"]},
            "rules": arr("set", _RULE),
            "scope_check": obj(
                {
                    "authorized": {"type": "boolean"},
                    "detail": {"type": "string", "maxLength": 2048},
                },
                ["authorized"],
            ),
            "blocked_reasons": arr("set", {"type": "string", "minLength": 1, "maxLength": 1024}),
        },
        "allOf": [
            {
                "if": {"type": "object", "properties": {"mode": {"const": "evidence_calibrated_bound"}}},
                "then": {
                    "type": "object",
                    "properties": {
                        "rules": {
                            "type": "array",
                            "items": {
                                "type": "object",
                                "properties": {"input_kind": {"not": {"const": "manual_override"}}},
                            },
                        },
                    },
                },
            },
            {
                "if": {"type": "object", "properties": {"mode": {"not": {"const": "qualitative_direction"}}}},
                "then": {
                    "type": "object",
                    "properties": {
                        "rules": {
                            "type": "array",
                            "items": {
                                "type": "object",
                                "properties": {"input_kind": {"not": {"const": "sequence_proxy"}}},
                            },
                        },
                    },
                },
            },
            {
                "if": {"type": "object", "properties": {"mode": {"not": {"const": "user_calibrated_bound"}}}},
                "then": {
                    "type": "object",
                    "properties": {
                        "rules": {
                            "type": "array",
                            "items": {
                                "type": "object",
                                "properties": {"input_kind": {"not": {"const": "manual_override"}}},
                            },
                        },
                    },
                },
            },
        ],
    },
)

_SCENARIO = {
    "type": "object",
    "additionalProperties": False,
    "required": ["name", "diffs", "fba", "model_hash", "diff_hash", "medium_artifact_id", "applied_rule_ids", "mapping_proof_ids", "target_metric"],
    "properties": {
        "name": {"type": "string", "minLength": 1, "maxLength": 256},
        "diffs": arr("set", obj(
            {
                "rule_id": {"type": "string", "minLength": 1, "maxLength": 128},
                "reaction_id": {"type": "string", "minLength": 1, "maxLength": 256},
                "old_value": dec(),
                "new_value": dec(),
                "unit": {"type": "string", "minLength": 1, "maxLength": 64},
            },
            ["rule_id", "reaction_id", "old_value", "new_value", "unit"],
        )),
        "fba": obj(
            {
                "status": {"enum": ["optimal", "infeasible", "unbounded", "non_optimal", "timeout", "not_run"]},
                "value": dec(),
            },
            ["status"],
        ),
        "fva": obj(
            {
                "intervals": arr("set", obj(
                    {
                        "reaction_id": {"type": "string", "minLength": 1, "maxLength": 256},
                        "min": dec(),
                        "max": dec(),
                    },
                    ["reaction_id", "min", "max"],
                )),
            },
            ["intervals"],
        ),
        "pfba": obj(
            {
                "status": {"enum": ["optimal", "infeasible", "unbounded", "non_optimal", "timeout", "not_run"]},
                "value": dec(),
            },
            ["status"],
        ),
        "model_hash": sha(),
        "diff_hash": sha(),
        "medium_artifact_id": sha(),
        "applied_rule_ids": arr("set", {"type": "string", "minLength": 1, "maxLength": 128}),
        "mapping_proof_ids": arr("set", sha()),
        "target_metric": {"type": "string", "minLength": 1, "maxLength": 256},
    },
}

SCHEMAS["consequence_run"] = schema(
    "consequence_run",
    "consequence_run@1 (direction is per claim_target; failed scenarios never yield ROBUST_DIRECTION)",
    {
        "type": "object",
        "additionalProperties": False,
        "required": ["artifact_type", "model_ref", "coupling_ref", "numeric_policy_ref", "medium_ref", "objective", "baseline", "scenarios", "claim_targets"],
        "properties": {
            "artifact_type": {"const": "consequence_run@1"},
            "model_ref": aref(),
            "coupling_ref": aref(),
            "numeric_policy_ref": aref(),
            "medium_ref": aref(),
            "objective": {"type": "string", "minLength": 1, "maxLength": 256},
            "baseline": obj(
                {
                    "feasible": {"type": "boolean"},
                    "status": {"enum": ["optimal", "infeasible", "unbounded", "non_optimal", "timeout", "not_run"]},
                    "objective_value": dec(),
                    "solver": obj(
                        {
                            "id": {"type": "string", "minLength": 1, "maxLength": 64},
                            "version": {"type": "string", "minLength": 1, "maxLength": 64},
                        },
                        ["id", "version"],
                    ),
                    "options": {"type": "object", "additionalProperties": True},
                },
                ["feasible", "status", "solver"],
            ),
            "scenarios": arr("set", _SCENARIO),
            "claim_targets": arr("set", obj(
                {
                    "kind": {"enum": ["growth", "product", "reaction"]},
                    "reaction_id": {"type": "string", "maxLength": 256},
                    "direction": {"enum": ["ROBUST_DIRECTION", "MIXED", "INDETERMINATE", "NOT_RUN"]},
                    "claim_id": sha(),
                },
                ["kind", "direction"],
            )),
            "diagnostics": {"type": "string", "maxLength": 4096},
        },
    },
)

SCHEMAS["tier_decision"] = schema(
    "tier_decision",
    "tier_decision@1 (operation-level, recomputed from snapshot; input_snapshot_id points at the parent snapshot only)",
    {
        "type": "object",
        "additionalProperties": False,
        "required": ["artifact_type", "policy_id", "policy_version", "policy_hash", "input_snapshot_id", "per_operation"],
        "properties": {
            "artifact_type": {"const": "tier_decision@1"},
            "policy_id": {"type": "string", "minLength": 1, "maxLength": 128},
            "policy_version": {"type": "string", "minLength": 1, "maxLength": 64},
            "policy_hash": sha(),
            "input_snapshot_id": sha(),
            "input_artifact_ids": arr("set", sha()),
            "per_operation": arr("set", obj(
                {
                    "operation": {"type": "string", "minLength": 1, "maxLength": 64},
                    "max_tier": {"enum": ["reference_profile", "transfer_profile", "structural_only", "blocked"]},
                    "gates": arr("set", check()),
                    "decision": {"enum": ["allow", "deny"]},
                    "capabilities": arr("set", {"type": "string", "minLength": 1, "maxLength": 64}),
                    "reason_codes": arr("set", {"type": "string", "minLength": 1, "maxLength": 64}),
                },
                ["operation", "max_tier", "gates", "decision", "capabilities", "reason_codes"],
            )),
            "gaps": arr("set", {"type": "string", "minLength": 1, "maxLength": 1024}),
        },
    },
)
