"""Verify and present the sealed public scenario records; standard library only.

This checks retained evidence consistency. It does not verify an archived JWT
signature offline or grant approval. Live GitLab links retain execution origin.
"""
from __future__ import annotations
import argparse
import hashlib
import io
import json
from pathlib import Path, PurePosixPath
import zipfile

ARCHIVE_SHA256 = '2d7d2443351bbeab24f0f7d9afdefde428925e7f2c18fbc538b02a5cc537d0d5'
MANIFEST_SHA256 = 'a410797c0fde241758ef6bbe5edd039f5cf668b8ba78e38551a060132b58d2ba'
APP = 'https://gitlab.com/gitlab-ai-hackathon/transcend-october-2026/2155912/release-guardian'
VERIFICATION = APP + '-verification'
EVIDENCE_COMMIT = '89f70aa82d3a0b42f85841695fcbc96ab042de33'
POLICY = '22a25f5374e45a60c2cde66e2601f4187ffcf48d'
CASES = {
    'price': ('Integer price contract', '1009ae34a2816a59fd65dfd27c699ce8ee0c2591', 2992694260, 2),
    'legacy': ('Persisted legacy retry', '18fbcc0b3dda47a86ef23de4a55b217924b0c967', 2992743695, 3),
    'rollback': ('Original-backend rollback', '4b09366972794649970dd9736d9ba85a94098522', 2992883199, 4),
    'atomic': ('First repair activation', '269f14f3d97929ed7c41cdabc45054ce03455331', 2992675600, 5),
    'header': ('Case-insensitive HTTP header', 'b1227166abb5d20eb24c0f42f4ab59e2fc8ee951', 2992848209, 6),
}


def digest(raw):
    return hashlib.sha256(raw).hexdigest()


def require(value, message):
    if not value:
        raise ValueError('Public evidence: ' + message)


def verify_archive(raw):
    require(len(raw) <= 1_000_000 and digest(raw) == ARCHIVE_SHA256, 'archive does not match the reviewed package')
    with zipfile.ZipFile(io.BytesIO(raw)) as archive:
        infos = archive.infolist()
        require(len(infos) == 37 and sum(i.file_size for i in infos) < 2_000_000, 'archive inventory exceeds bounds')
        names = [i.filename for i in infos]
        require(len(set(n.casefold() for n in names)) == len(names), 'duplicate archive path')
        for info in infos:
            parts = PurePosixPath(info.filename).parts
            require(not info.is_dir() and not info.flag_bits & 1 and info.file_size <= 500_000
                    and not info.filename.startswith('/') and '\\' not in info.filename
                    and all(p not in ('.', '..') for p in parts), 'unsafe archive member')
        files = {i.filename: archive.read(i) for i in infos}
    manifest_raw = files['evidence/public-scenarios/manifest.json']
    require(digest(manifest_raw) == MANIFEST_SHA256, 'publication manifest changed')
    manifest = json.loads(manifest_raw)
    require(set(files) == set(manifest['files']) | {'evidence/public-scenarios/manifest.json'}, 'file coverage changed')
    for name, expected in manifest['files'].items():
        require(digest(files[name]) == expected, 'file hash differs: ' + name)
    return verify_records(files), files


def verify_records(files):
    read = lambda path: json.loads(files['evidence/public-scenarios/' + path])
    rows = []
    for case, (title, sha, pipeline, mr) in CASES.items():
        value = read(case + '/result.json')
        require(value['case'] == case and value['project_id'] == 88136083
                and value['candidate_sha'] == sha and value['pipeline_id'] == pipeline
                and value['merge_request_iid'] == mr and value['policy_definition_sha'] == POLICY,
                'candidate or policy binding differs for ' + case)
        require(value['all_five_producers_passed'] and value['raw_artifacts_and_source_hashes_verified']
                and value['gate_recomputation_passed'] and value['candidate_parent_verified']
                and value['recovery_checks'] == {'passed': 11, 'required': 11}
                and value['protocol_checks'] == {'passed': 2, 'required': 2}, 'required gate differs')
        require(not value['approval_performed_by_agent'] and not value['merge_performed_by_agent'], 'human boundary differs')
        sessions = value['sessions']
        require(len(sessions) == 2 and sessions[0]['stage'] == 'zero-model-preflight'
                and sessions[1]['stage'] == 'single-bounded-repair'
                and all(s['native_identity_verified'] for s in sessions), 'native session attribution differs')
        repair = sessions[1]
        require(repair['observed_created_commit_sha'] == sha and len(repair['code_tool_calls']) == 1
                and repair['code_tool_calls'][0]['files'] == value['changed_files'], 'commit tool attribution differs')
        rows.append({'case': case, 'title': title, 'candidate_sha': sha, 'pipeline_id': pipeline,
                     'merge_request_iid': mr, 'native_session_id': repair['id'],
                     'native_pipeline_id': repair['pipeline_id'], 'failed_source': value['failed_source'],
                     'failed_pipeline_id': value['failed_pipeline_id'], 'changed_files': value['changed_files'],
                     'producer_jobs': value['producer_job_ids'], 'status': 'passed',
                     'owner_state': 'approved_and_merged' if case == 'atomic' else 'evaluation_unapproved_unmerged',
                     'links': {'mr': APP + '/-/merge_requests/' + str(mr),
                               'repair': APP + '/-/commit/' + sha,
                               'ci': APP + '/-/pipelines/' + str(pipeline),
                               'duo': APP + '/-/pipelines/' + str(repair['pipeline_id']),
                               'failed_ci': APP + '/-/pipelines/' + str(value['failed_pipeline_id'])}})
    approval, merge = read('atomic/owner-approval-verification.json'), read('atomic/owner-merge.json')
    candidate = CASES['atomic'][1]
    require(approval['status'] == 'verified' and approval['candidate_sha'] == merge['candidate_sha'] == candidate
            and approval['pipeline_id'] == 2992675600 and approval['approval_job_id'] == merge['approval_job_id'] == 17491079998
            and approval['approver'] == 'atik97' and approval['policy_definition_sha'] == POLICY
            and approval['approval_artifact_sha256'] == '7588bda2eb32a5fc75b0ab7d205ca6b3df6feb717b1585e82465edf00715407e'
            and merge['merge_commit_sha'] == '642a61fcb672a0a4c51d6d9c81011a5b91291bf8'
            and merge['merge_parent_ids'] == ['b93247fe053913be62572d1cb68a1f42b9c46ffa', candidate]
            and merge['approved_candidate_is_direct_parent'], 'owner approval or merge differs')
    refusal = read('refusal/verification.json')
    require(refusal['status'] == 'verified' and refusal['branch_unchanged'] and not refusal['code_commit_created']
            and refusal['write_tools_available'] == 0 and refusal['signed_origin_status'] == 'passed'
            and refusal['assessment_session_id'] == 10103931, 'refusal boundary differs')
    blocked = [read('rollback/' + name + '-proposal-blocked.json') for name in ('first', 'second')]
    require([b['proposal_commit'] for b in blocked] == ['1daacc0fc118e714b28469ea41b56b3df705674a', '6bbaaf8bba3e6b7d1652b3656954f0a70781c81e'], 'blocked proposal identity differs')
    require(all(not b['approval_performed'] and not b['merge_performed'] for b in blocked), 'rejected proposal was approved')
    return {'kind': 'guardian-current-public-installation', 'date': '27 October 2026',
            'project_id': 88136083, 'verification_project_id': 88136094, 'scenarios': rows,
            'principal_case': 'atomic', 'approval': approval, 'merge': merge,
            'refusal': refusal, 'blocked_proposals': blocked,
            'counts': {'successful_repair_scenarios': 5, 'code_producing_attempts': 7,
                       'read_only_model_assessments': 1, 'successful_zero_model_preflights': 8,
                       'failed_zero_model_preflights': 1},
            'evidence_archive_sha256': ARCHIVE_SHA256,
            'evidence_index': VERIFICATION + '/-/blob/' + EVIDENCE_COMMIT + '/docs/public-scenarios-20261027.md',
            'historical_projects': [APP.replace('/release-guardian', '/compatibility-technical-test'),
                                    APP.replace('/release-guardian', '/release-guardian-policy')],
            'offline_jwt_signature_verification': False, 'model_called_by_website': False}


def validate_witness(value):
    from .public_receipt_worker import COMMITS, PIN_SHA256
    require(value['kind'] == 'guardian-current-receipt-witness' and value['source_archive_sha256'] == PIN_SHA256
            and value['model_called'] is False and value['gitlab_called'] is False, 'receipt replay scope differs')
    require([c['client_protocol'] for c in value['clients']] == ['1.0.0', '2.0.0'], 'receipt protocol coverage differs')
    for client in value['clients']:
        require([v['label'] for v in client['versions']] == ['before', 'repaired'], 'receipt source coverage differs')
        for version in client['versions']:
            repaired = version['label'] == 'repaired'
            require(version['source_commit'] == COMMITS[version['label']] and version['client_protocol'] == client['client_protocol'], 'receipt source binding differs')
            accepted = version['accepted']
            require(len(accepted) == 4 and len({(a['account'], a['operation_id']) for a in accepted}) == 4
                    and len({a['response']['body']['orderId'] for a in accepted}) == 4
                    and all(a['response']['status'] == 201 and a['acknowledgment_discarded'] is True for a in accepted), 'distinct accepted purchases differ')
            initial, final = version['initial_orders'], version['final_orders']
            require(set(initial) == set(final) == {'alice', 'bob'} and sum(len(x) for x in initial.values()) == version['initial_count'] == 4, 'initial account coverage differs')
            require(sum(len(x) for x in final.values()) == version['final_count'] == (4 if repaired else 5), 'stored purchase count differs')
            receipt = version['retry']['response']
            original = accepted[0]['response']['body']['orderId']
            require(version['retry']['account'] == accepted[0]['account'] and version['retry']['operation_id'] == accepted[0]['operation_id'], 'retried operation differs')
            require((receipt['body']['orderId'] == original) is repaired and receipt['body']['replayed'] is repaired
                    and receipt['status'] == (200 if repaired else 201) and version['receipt_preserved'] is repaired, 'receipt preservation verdict differs')
            for account in ('alice', 'bob'):
                accepted_ids = sorted(a['response']['body']['orderId'] for a in accepted if a['account'] == account)
                require(sorted(r['orderId'] for r in initial[account]) == accepted_ids, 'initial stored receipts differ from accepted purchases')
                final_ids = accepted_ids + ([receipt['body']['orderId']] if not repaired and account == accepted[0]['account'] else [])
                require(sorted(r['orderId'] for r in final[account]) == sorted(final_ids), 'final stored receipts differ from observed retry')
            require(not repaired or initial == final, 'repair changed accepted purchase inventory')
    return value


def assets():
    raw = Path(__file__).with_name('data').joinpath('public-scenario-evidence.zip').read_bytes()
    summary, files = verify_archive(raw)
    # Validate text before the binary archive is admitted to the public package.
    from .public_data import privacy_check
    for text in files.values():
        privacy_check(text)
    witness_raw = Path(__file__).with_name('data').joinpath('current-receipt-witness.json').read_bytes()
    validate_witness(json.loads(witness_raw))
    return {'current-receipt-witness.json': witness_raw,
            'public-installation.json': (json.dumps(summary, sort_keys=True) + '\n').encode(),
            'guardian-public-evidence.zip': raw,
            'verify-public-evidence.py': Path(__file__).read_bytes()}


def main():
    parser = argparse.ArgumentParser(description=__doc__)
    parser.add_argument('archive', type=Path)
    args = parser.parse_args()
    summary, files = verify_archive(args.archive.read_bytes())
    print(json.dumps({'status': 'verified', 'files': len(files), 'archive_sha256': ARCHIVE_SHA256,
                      'counts': summary['counts'], 'approved_candidate': summary['approval']['candidate_sha'],
                      'offline_jwt_signature_verification': False}, indent=2))


if __name__ == '__main__':
    main()
