#!/usr/bin/env python3
"""Habit DB/HTTP comparison; isolated queue capture is not worker acceptance."""
import importlib.util
import json
from pathlib import Path
import re
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 = ['DETAIL_DEFAULT', 'SET_HABIT_INSERT', 'DETAIL_SELECTED3', 'SET_HABIT_UPDATE',
         'SET_HABIT_REPEAT', 'DETAIL_SELECTED4', 'RPE_EMPTY', 'RPE_MISSING_REJECT',
         'RPE_RANGE_INSERT', 'RPE_TWO_DATES', 'RPE_OVERLAP_REJECT', 'RPE_REPLACE_FIRST',
         'RPE_REPLACED_FIRST', 'RPE_SECOND_UNCHANGED']
expected = ['PILOT_HAB_' + 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']) == 28
    assert [c['scenario'] for c in data['cases']] == expected
    for case in data['cases']:
        assert case['http_status'] == 200 and case['trace_format_valid'] is True
        if case['scenario'].endswith('RPE_MISSING_REJECT'):
            assert case['body']['status'] == 500 and case['body']['message'] == '开日日期不能为空'
        elif case['scenario'].endswith('RPE_OVERLAP_REJECT'):
            assert case['body']['status'] == 500 and case['body']['message'] == '训练时间不能交叉重复'
        else:
            assert case['body']['status'] == 200
        assert case['raw_json_shape']['object']['status'] == 'number'
        if case['path'].endswith('/detail'):
            for enum in case['body']['data']['detail']:
                assert isinstance(enum['enum_key'], str) and isinstance(enum['ratio'], str)
                assert re.fullmatch(r'-?\d+\.\d{2}', enum['ratio'])
                assert type(enum['checked']) is int and enum['checked'] in (0, 1)
        if case['path'].endswith(('setHabit', 'setRpe')):
            assert case['body']['data'] == [] and case['raw_json_shape']['object']['data'] == {'array': []}
    cleanup = data['cleanup']
    assert cleanup['fresh_pdo_owned_rows'] == {'staff': 0, 'habit': 0, 'habit_rpe': 0, 'habit_rpe_info': 0}
    assert cleanup['tokens_absent'] is True and cleanup['natural_tables_and_enum_unchanged'] is True
    assert cleanup['health_targets_unchanged'] is True and data['real_queue_or_staff_power_executed'] is False
    assert len(data['queue_captures']) == 3
    for event in data['queue_captures']:
        assert event['kind'] == 'pushJump' and event['action'] == 'staffPower'
        assert event['staff_id'] == 1 and event['store_id'] == 2147000421
        assert event['owned_parameters_valid'] is True and event['real_queue_executed'] is False
        assert re.fullmatch(r'\d{4}-\d{2}-\d{2}', event['date'])
    assert len(data['boundary_findings']) == 2
    for boundary in data['boundary_findings']:
        assert boundary['business_status'] == 500 and boundary['strict_scalar_type_error'] is True
        assert boundary['original_rows_unchanged'] is True
        assert not any(e.get('kind') == 'query_observed' and e['scenario'] == boundary['scenario'] for e in data['events'])
    ends = [e for e in data['events'] if e.get('kind') == 'request_end']
    assert len(ends) == 30 and all(e['fatal'] is False for e in ends)
    assert len(data['snapshot_scan_metrics']) == 2
    assert all(v['streamed'] is True for v in data['source_before'].values())
    return data

def main():
    b, c = checked(sys.argv[1], 'B'), checked(sys.argv[2], 'C')
    differences = strict.compare(b['cases'], c['cases'])
    differences += strict.compare(b['queue_captures'], c['queue_captures'], '$.queue_captures')
    differences += strict.compare(b['boundary_findings'], c['boundary_findings'], '$.boundary_findings')
    source_maps = []
    lanes = {}
    for lane, data in [('B', b), ('C', c)]:
        queries = [e for e in data['events'] if e.get('kind') == 'query_observed']
        sources = {}
        for event in queries:
            assert isinstance(event.get('fingerprint_lexical_warning'), bool)
            for path, sha in event.get('source_hashes', {}).items():
                assert path not in sources or sources[path] == sha
                sources[path] = sha
        source_maps.append(sources)
        lanes[lane] = {'queries': len(queries), 'fingerprints': len({e['fingerprint'] for e in queries}),
                       'lexical_warnings': sum(e['fingerprint_lexical_warning'] for e in queries),
                       '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'],
                       'scan_metrics': data['snapshot_scan_metrics']}
    shared = source_maps[0].keys() & source_maps[1].keys()
    assert shared and all(source_maps[0][p] == source_maps[1][p] for p in shared)
    result = {'status': 'PASS' if not differences else 'FAIL', 'complete_contract_case_pairs': 28,
              'positive_pairs': 24, 'expected_refusal_pairs': 4, 'shared_boundary_failures': 2,
              'actual_positive_methods_paths': sorted({x['method'] + ' ' + x['path'] for x in b['cases']}),
              'shared_source_files_same_sha': len(shared), 'differences': differences, 'lanes': lanes,
              'scope': 'Four-table Habit/RPE HTTP DB path; queue captured only, not real worker/energy recomputation acceptance'}
    print(json.dumps(result, ensure_ascii=False, indent=2, default=str))
    return bool(differences)

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