#!/usr/bin/env python3
"""Root one-time integration of four real, owned nutrition report reads."""
from decimal import Decimal
import json
from pathlib import Path
import subprocess
import sys
import integrate_20261010 as tool
from integrate_20261011_batches40_42 import run, sha
from integrate_20261011_batches46_48 import item

BASE = tool.STORE + 'parallel-store-nutrition-reports-read24-20261011/'
PIN = '9f5b90ed39817a5afc92cde54607eac7fcb97359cedc61d924cb9e495912581e'
PLAN = 'fbd43e6c40efec4f71f943d822faeff1fc4fcab5f0b7cb875a706699edfccd12'
ACTIONS = ['get_day_teampower_popout', 'get_day_teamnutrient_popout',
           'get_stage_teampower_popout', 'get_stage_team_nutrient_popout']

def verify():
    root = tool.ROOT / BASE
    assert sha(root / 'manifest.json') == PIN
    manifest = tool.load(BASE + 'manifest.json')
    assert len(manifest['files']) == 82
    assert manifest['public_files'] == 24 and manifest['private_files'] == 58
    for record in manifest['files']:
        relative = Path(record['path'])
        assert not relative.is_absolute() and '..' not in relative.parts
        path = root / relative
        assert path.is_file() and not path.is_symlink()
        assert path.stat().st_size == record['bytes'] and sha(path) == record['sha256']
        if record['private']:
            assert relative.parts[0] == 'private' and path.stat().st_mode & 0o777 == 0o600
            parent = path.parent
            while parent != root:
                assert not parent.is_symlink() and parent.stat().st_mode & 0o777 == 0o700
                parent = parent.parent
    result = json.loads(run(BASE, sys.executable, 'verify.py'))
    assert result['HTTP'] == result['wire'] == 24
    assert result['actual_native_events'] == 528
    assert result['assertions'] == 1457 and result['DTO_mutations_rejected'] == 18
    assert result['full_BC_body_pairs'] == 12 and result['business_DML_DDL'] == 0
    assert result['sentinel_drift_not_attributed_to_this_readonly_batch']
    assert result['sentinel_drift']['C'] == {}
    assert set(result['sentinel_drift']['B']) == {'menu_recommend'}
    gate = subprocess.run(['docker', 'exec', 'zhctapp_v2_0', '/usr/local/php7.3/bin/php',
        '/workspace/zhct/zhctprompt/' + BASE + 'test-gate.php'], check=True, capture_output=True, text=True)
    assert json.loads(gate.stdout) == {'gate_assertions': 19, 'passed': True}
    assert sha(root / 'fixture-plan-first4.json') == PLAN
    plan = tool.load(BASE + 'fixture-plan-first4.json')
    assert plan['per_lane']['INSERT'] == len(plan['rows']) == 6
    for lane in 'BC':
        journal = tool.load(BASE + f'private/{lane}/fixture-journal.json')
        assert journal['approved_plan_sha256'] == PLAN and journal['committed']
        assert len(journal['events']) == 6
        for expected, event in zip(plan['rows'], journal['events']):
            assert event['queryString'] == expected['sql']
            assert event['binds'] == expected['pdo_binds']
            assert event['sent'] and event['success'] and event['rowCount'] == 1
            # Native fixture types differ legitimately; this checks physical input values,
            # never normalizes the real HTTP DTO or business numeric contract.
            for field, value in expected['values'].items():
                actual = event['original_row'][field]
                if field in {'create_time', 'update_time'}:
                    assert actual == value or actual == value + '.000000'
                elif isinstance(value, (int, float)) or (isinstance(value, str)
                        and field in {'height', 'weight', 'energy', 'carbohydrate', 'protein',
                            'fat', 'dietary_fiber', 'va', 'vb1', 'vb2', 'vpp', 'vc', 've',
                            'potassium', 'sodium', 'calcium', 'magnesium', 'iron', 'zinc',
                            'total_power', 'recommend_power', 'morning_power', 'noon_power',
                            'night_power', 'carbohydrate_weight', 'protein_weight', 'fat_weight',
                            'prescription_power', 'prescription_carbohydrate', 'prescription_protein',
                            'prescription_fat', 'carbohydrate_ratio', 'protein_ratio', 'fat_ratio', 'number'}):
                    assert Decimal(str(actual)) == Decimal(str(value)), (lane, field)
                else:
                    assert actual == value, (lane, field)
        cleanup = tool.load(BASE + f'private/{lane}/auth-cleanup.json')
        assert cleanup['original_cache_clean_called'] and cleanup['runtime_request_removed']
        assert cleanup['DB_DML'] == 0 and not cleanup['stateless_token_globally_revoked']
        final = tool.load(BASE + f'private/{lane}/final.json')
        assert final['own_rows_unchanged'] and final['sentinel_is_not_natural_full_sha']
    sources = tool.load(BASE + 'source-lock.json')
    assert len(sources) == 957
    for relative, digest in sources.items():
        assert sha(tool.ROOT.parent / 'zhctproject/store/application' / relative) == digest, relative
    for record in manifest['files']:
        assert sha(root / record['path']) == record['sha256']

def targets():
    return [item('store', 'POST', '/p/stageanalyze/' + action, BASE,
        risk='readonly-owned-staff-three-meals-and-recommendation-independent-complete-DTO',
        request_type='application/x-www-form-urlencoded-original-post',
        parity='partial-12-complete-BC-wire-byte-identical-pairs-1457-assertions-18-mutations',
        boundary_empty_min_max='partial-positive-own-missing-UUID-and-type2-no-all-input-claim',
        cleanup='marked-six-rows-per-lane-retained-own-worker-cache-request-cleared-stateless-global-revoke-unproven')
        for action in ACTIONS]

if __name__ == '__main__':
    audit = Path(__file__).with_name('integration-20261011-batch68.json')
    assert not audit.exists(), 'Preserve original transition audit'
    tool.main(targets(), audit, verify)
