from __future__ import annotations

REQUIRED=['agent_id', 'agent_version', 'purpose', 'owner_ref', 'input_schema_ref', 'output_schema_ref', 'structured_output_mode', 'tool_contract_ids', 'handoff_contract_ids', 'authority_class', 'allowed_actions', 'forbidden_actions', 'data_classification', 'memory_boundary_ref', 'guardrail_refs', 'failure_states', 'retry_contract_ref', 'compatibility_state', 'deprecation_state', 'catalog_status', 'evidence_ref']
MISSING={None,"","MISSING","UNSET"}
ALLOWED_STATUS={"ACTIVE","HOLD","DEPRECATED","INCOMPATIBLE"}
ALLOWED_COMPAT={"COMPATIBLE","REVIEW_REQUIRED","INCOMPATIBLE","UNKNOWN"}
HIGH_IMPACT_MARKERS=("execute","delete","publish","refund","payment","write_external","admin")

def _set(v):
    if isinstance(v,list): return {str(x).strip() for x in v if str(x).strip()}
    return {x.strip() for x in str(v or '').split(',') if x.strip() and x.strip().upper() not in {'NONE','N/A','NA'}}

def _major(version):
    try: return int(str(version).split('.')[0])
    except Exception: return -1

def evaluate(row):
    missing=[k for k in REQUIRED if row.get(k) in MISSING]
    if missing: return {"state":"HOLD_EVIDENCE_MISSING","missing":missing}
    if row['catalog_status'] not in ALLOWED_STATUS: return {"state":"HOLD_CATALOG_STATUS_INVALID"}
    if row['compatibility_state'] not in ALLOWED_COMPAT: return {"state":"HOLD_COMPATIBILITY_STATE_INVALID"}
    if str(row['memory_boundary_ref']).upper() in {'NONE','UNKNOWN','UNBOUNDED'}:
        return {"state":"HOLD_MEMORY_BOUNDARY_MISSING"}
    prev_ver=str(row.get('previous_agent_version') or row['agent_version'])
    prev_out=str(row.get('previous_output_schema_ref') or row['output_schema_ref'])
    prev_in=str(row.get('previous_input_schema_ref') or row['input_schema_ref'])
    if str(row['output_schema_ref']) != prev_out and str(row['agent_version']) == prev_ver:
        return {"state":"HOLD_VERSION_NOT_INCREMENTED"}
    if str(row.get('input_optional_to_required','false')).lower() in {'true','1','yes'}:
        if row['compatibility_state'] not in {'INCOMPATIBLE','REVIEW_REQUIRED'} or row['catalog_status']=='ACTIVE':
            return {"state":"HOLD_INPUT_BREAKING_CHANGE_NOT_MARKED"}
    tools=_set(row['tool_contract_ids']); prev_tools=_set(row.get('previous_tool_contract_ids',''))
    added=tools-prev_tools
    high={t for t in added if any(m in t.lower() for m in HIGH_IMPACT_MARKERS)}
    if high:
        auth=str(row['authority_class']).upper(); allowed=','.join(_set(row['allowed_actions'])).lower()
        if auth in {'READ_ONLY','READ_RECOMMEND','DRAFT_ONLY'} or not all(any(m in t.lower() and m in allowed for m in HIGH_IMPACT_MARKERS) for t in high):
            return {"state":"HOLD_AUTHORITY_NOT_RECOMPUTED","tools":sorted(high)}
    handoffs=_set(row['handoff_contract_ids']); prev_handoffs=_set(row.get('previous_handoff_contract_ids',''))
    removed=prev_handoffs-handoffs
    required_by_consumer=_set(row.get('consumer_required_handoffs',''))
    if removed & required_by_consumer:
        return {"state":"HOLD_HANDOFF_DEPENDENCY_BROKEN","handoffs":sorted(removed & required_by_consumer)}
    consumer_schema=str(row.get('consumer_expected_output_schema_ref') or row['output_schema_ref'])
    if consumer_schema != str(row['output_schema_ref']):
        if row['compatibility_state'] not in {'INCOMPATIBLE','REVIEW_REQUIRED'} or row['catalog_status']=='ACTIVE':
            return {"state":"HOLD_CONSUMER_SCHEMA_MISMATCH"}
    if row['compatibility_state']=='UNKNOWN' and row['catalog_status']=='ACTIVE':
        return {"state":"HOLD_COMPATIBILITY_UNKNOWN"}
    if str(row['deprecation_state']).upper() in {'DEPRECATED','SUNSET'} and row['catalog_status']=='ACTIVE':
        return {"state":"HOLD_DEPRECATION_STATE_CONFLICT"}
    if str(row.get('baseline_decision_reused','false')).lower() in {'true','1','yes'}:
        return {"state":"HOLD_BASELINE_ORACLE_REUSE"}
    if row['catalog_status']=='INCOMPATIBLE' or row['compatibility_state']=='INCOMPATIBLE':
        if str(row.get('transfer_case','false')).lower() in {'true','1','yes'}:
            return {"state":"TRANSFER_INCOMPATIBLE_RECOMPUTED"}
        return {"state":"BOUNDED_INCOMPATIBLE"}
    if row['catalog_status']=='HOLD': return {"state":"BOUNDED_HOLD"}
    if row['catalog_status']=='DEPRECATED': return {"state":"BOUNDED_DEPRECATED"}
    return {"state":"ACTIVE_COMPATIBLE"}
