#!/usr/bin/env python3
"""Complete Article response/shape comparison. Never ignore counters or store_id."""
import importlib.util
import json
from pathlib import Path
import sys

here = Path(__file__).resolve().parent
spec = importlib.util.spec_from_file_location('strict', here.parents[2] / 'work/2026-09-28-smart-canteen-dm8-poc/http-harness/strict_response_compare.py')
strict = importlib.util.module_from_spec(spec)
spec.loader.exec_module(strict)
steps = ['LIST_EMPTY', 'ADD_IMAGE_ZERO_REJECT', 'ADD_CONTENT_EMPTY_REJECT', 'ADD_LONG_JSON',
         'DETAIL_LONG', 'DETAIL_LONG_REPEAT', 'ADD_SECOND_FORM', 'LIST_TWO', 'LIST_STATUS_ZERO',
         'LIST_STATUS_ONE', 'LIST_CATEGORY', 'LIST_TITLE_LONG', 'EDIT_IMAGE_ZERO_REJECT',
         'EDIT_CONTENT_EMPTY_REJECT', 'EDIT_FIRST_FORM', 'DETAIL_EDITED', 'LIST_REORDERED',
         'DELETE_FIRST', 'DETAIL_SOFT_STATE', 'LIST_ONE', 'REPEAT_DELETE_FIRST', 'DELETE_SECOND', 'LIST_EMPTY_AFTER']
expected = ['PILOT_AR_' + module + '_' + step for module in ['STORE', 'TERMINAL'] for step in steps]

def checked(path, lane):
    data = strict.load_json(path)
    assert data['lane'] == lane and data['boundary_verified'] is True and data['error'] is None
    assert data['case_count'] == len(data['cases']) == 46
    assert [case['scenario'] for case in data['cases']] == expected
    assert data['triggers'] == data['foreign_keys'] == 0
    assert set(data['metadata']) == {'article_category', 'article', 'upload_file'}
    assert all(all(v is True for v in gate.values()) for gate in data['metadata'].values())
    for case in data['cases']:
        assert case['http_status'] == 200 and case['trace_format_valid'] is True
        if case['scenario'].endswith('IMAGE_ZERO_REJECT'):
            assert case['body']['status'] == 500 and case['body']['message'] == '请上传封面图'
        elif case['scenario'].endswith('CONTENT_EMPTY_REJECT'):
            assert case['body']['status'] == 500 and case['body']['message'] == '请输入文章内容'
        else:
            assert case['body']['status'] == 200
        raw = case['raw_json_shape']['object']
        assert raw['status'] == 'number' and raw['trace_id'] == 'string'
        if case['method'] == 'POST':
            assert case['body']['data'] == [] and raw['data'] == {'array': []}
        else:
            assert 'object' in raw['data']
    cleanup = data['cleanup']
    assert cleanup['fresh_pdo_owned_rows'] == {'article_category': 0, 'article': 0, 'upload_file': 0}
    assert cleanup['tokens_absent'] is True and cleanup['natural_tables_unchanged'] is True
    assert cleanup['unexpected_references'] == 0 and cleanup['reference_columns_examined'] > 0
    assert len(data['counter_checks']) == 8
    for count in data['counter_checks']:
        assert count['counter_delta'] == 0 and count['before_actual_views'] == count['after_actual_views'] == 3
        assert count['http_show_views'] == count['after_actual_views'] + count['virtual_views']
    assert len(data['diagnostics']) == 2
    assert all(d['source_bytes'] == d['expected_bytes'] > 32768 and d['source_sha'] == d['expected_sha']
               for d in data['diagnostics'].values())
    ends = [event for event in data['events'] if event.get('kind') == 'request_end']
    assert len(ends) == 46 and all(event['fatal'] is False for event in ends)
    return data

def hashes(data):
    out = {}
    for event in data['events']:
        for path, sha in event.get('source_hashes', {}).items():
            assert path not in out or out[path] == sha
            out[path] = sha
    return out

def main():
    b, c = checked(sys.argv[1], 'B'), checked(sys.argv[2], 'C')
    bh, ch = hashes(b), hashes(c)
    common = sorted(bh.keys() & ch.keys())
    assert common and all(bh[path] == ch[path] for path in common)
    differences = strict.compare(b['cases'], c['cases'])
    differences += strict.compare(b['counter_checks'], c['counter_checks'], '$.counter_checks')
    differences += strict.compare(b['diagnostics'], c['diagnostics'], '$.diagnostics')
    lanes = {}
    for lane, data in [('B', b), ('C', c)]:
        queries = [e for e in data['events'] if e.get('kind') == 'query_observed']
        assert all(isinstance(e.get('fingerprint_lexical_warning'), bool) for e in queries)
        lanes[lane] = {'queries': len(queries), 'fingerprints': len({e['fingerprint'] for e in queries}),
                       'lexical_warnings': sum(e['fingerprint_lexical_warning'] for e in queries),
                       'warning_scenarios': sorted({e['scenario'] for e in queries if e['fingerprint_lexical_warning']}),
                       'operations': {op: sum(e['operation'] == op for e in queries)
                                      for op in ['select', 'insert', 'update', 'delete', 'other']},
                       'cleanup': data['cleanup'], 'source_snapshot': data['source_before']}
    result = {'status': 'PASS' if not differences else 'FAIL', 'complete_response_case_pairs': 46,
              'positive_pairs': 38, 'expected_rejection_pairs': 8, 'counter_readback_pairs': 8,
              'actual_methods_paths': sorted({x['method'] + ' ' + x['path'] for x in b['cases']}),
              'shared_source_sha_equal': {path: bh[path] for path in common},
              'differences': differences, 'lanes': lanes,
              'scope': 'Own three-table Article HTTP only; upload metadata fixture SQL is not UploadFile ORM/upload acceptance'}
    print(json.dumps(result, ensure_ascii=False, indent=2, default=str))
    return bool(differences)

if __name__ == '__main__':
    raise SystemExit(main())
