#!/usr/bin/env python3
"""Owned meal chain and config decimal response fix; never replay writes."""
import hashlib
import json
import subprocess
from pathlib import Path
import integrate_20261010 as tool
from integrate_20261011_batches46_48 import item
from integrate_20261012_batch148 import shape

HERE = Path(__file__).resolve().parent
PRIVATE = Path('/private/tmp/cdx-ai-hk-course-b.Kmdirn')
BASE = 'work_ai_api/2026-09-30-dm8-interface-acceptance/parallel-owned-meal-chain-20261012/'
WRITES = ['/terminal/meal.Meal/add', '/terminal/meal.Meal/addMeal',
          '/store/meal.Meals/add', '/store/meal.Meals/addMealConfig']


def verify():
    manifest = PRIVATE / 'MEAL153_MANIFEST_20261012.json'
    assert hashlib.sha256(manifest.read_bytes()).hexdigest() == '9c3217108e404bc91008903601de639073b9cc49cbd32bed238666284ab33181'
    m = json.loads(manifest.read_text())
    for path, digest in m['assets_sha256'].items():
        assert '..' not in Path(path).parts
        assert hashlib.sha256((PRIVATE / path).read_bytes()).hexdigest() == digest
    for path, digest in m['approved_business_source'].items():
        assert hashlib.sha256((tool.source_root('ai_api') / path).read_bytes()).hexdigest() == digest
    for file, status in [('verify_meal153_receipts.php', 'verified_db_flow_response_type_red'),
                         ('verify_meal153_config_get_recheck.php', 'verified_fixed2_b_c_full_contract')]:
        result = json.loads(subprocess.check_output(['/opt/homebrew/opt/php@7.4/bin/php', str(PRIVATE / file)]))
        assert result['status'] == status
    cases = [
        ('B', 'meal153-chain-v2-3be25ec1ccd0dfeb5094fc5678281241f5aa3ed664be79a9b6f144883aa020f2.json',
         'meal153-config-get-recheck-3be25ec1ccd0dfeb5094fc5678281241f5aa3ed664be79a9b6f144883aa020f2.json'),
        ('C', 'C_meal153_chain_v2_51735c.json', 'C_meal153_config_get_recheck_51735c.json'),
    ]
    trees = {}
    for lane, oldfile, newfile in cases:
        read = lambda name: {x['phase']: x for x in json.loads((PRIVATE / 'runtime' / name).read_text())['events']}
        old, new = read(oldfile), read(newfile)
        for path, digest in old['before_chain']['source_sha256'].items():
            assert path.startswith('app/') and '..' not in Path(path).parts
            root = tool.source_root('ai_api')
            data = ((root / path).read_bytes() if path != 'app/store/model/meal/MealConfig.php' else
                    subprocess.check_output(['git', '-C', str(root), 'show', 'ffd3d7ba:' + path]))
            assert hashlib.sha256(data).hexdigest() == digest
        for path in WRITES:
            hits = [x for phase, x in old.items() if phase.startswith('after_http_')
                    and x['method'] == 'POST' and x['path'].split('?')[0] == path]
            assert len(hits) == 1 and hits[0]['http'] == 200
            body = json.loads(hits[0]['raw_response_exact'])
            assert type(body['status']) is int and body['status'] == 200
            trees[lane, path] = shape(body)
        assert new['before_http']['scope_before'] == new['final_audit']['scope_after']
        assert new['before_http']['scope_before'] == old['final_audit']['scope_future']
        before = json.loads(old['after_http_store_MealsInfo_config']['raw_response_exact'])
        after = json.loads(new['after_http']['raw_response_exact'])
        before.pop('trace_id', None)
        after.pop('trace_id', None)
        if lane == 'C':
            row = before['data']['list'][0]['data'][0]['dishes'][0]
            assert row['dishes_weight'] == 100.5 and row['energy'] == 224.12
            row['dishes_weight'], row['energy'] = '100.50', '224.12'
        assert before == after and shape(before) == shape(after)
        trees[lane, 'config'] = shape(after)
    for key in WRITES + ['config']:
        assert trees['B', key] == trees['C', key]


if __name__ == '__main__':
    audit = HERE / 'integration-20261012-batch153.json'
    assert not audit.exists()
    specs = [item('ai_api', 'POST', path, BASE,
        risk='owned-staff-meal-write-replace-config-isolated-queue-no-real-consumer',
        readback='tested-pass-owned-meal-infos-config-transitions-and-source-staff-dish-unchanged',
        success_case='partial-evidence-single-owned-staff-single-dish-write-chain-async-calculation-not-run',
        parity='partial-evidence-original-write-response-types-and-fixed-two-decimal-config-read',
        cleanup='marked-staff-user-meal-rows-retained-old-meal-soft-deleted-tokens-absent-private-queue3-per-engine')
        for path in WRITES]
    for path in ['/terminal/meal.Meal/infos', '/store/meal.Meals/MealsInfo']:
        specs.append(item('ai_api', 'GET', path, BASE, evidence_only=True,
            risk='owned-readback-config-positive-normal-store-meal-children-empty-without-async-consumer'))
    tool.main(specs, audit, verify)
