#!/usr/bin/env python3
"""Package the current completed C1132--C1431 checkpoint without changing its journal.

The lead creates frozen manifests, PREDECESSOR.json, strategy reviews and research artifacts.
This helper creates a reading report, payload manifest, and consistent ZIP snapshot.
"""
from pathlib import Path
from datetime import datetime, timezone
import argparse
import hashlib
import json
import re
import zipfile

ROOT = Path(__file__).resolve().parent.parent
WORKSPACE = ROOT.parent
FIRST, LAST = 1132, 1431
STEP_COUNT = LAST - FIRST + 1


def require(condition, message):
    if not condition:
        raise RuntimeError(message)


def sha(data):
    return hashlib.sha256(data).hexdigest()


def main():
    parser = argparse.ArgumentParser(description=__doc__)
    parser.add_argument('--first', type=int, default=FIRST, help='First step displayed in the reading report; evidence retains the full current cycle')
    parser.add_argument('--through', type=int, help='Assert the current final completed step before packaging')
    parser.add_argument('--date', default=datetime.now(timezone.utc).strftime('%Y%m%d'))
    args = parser.parse_args()
    require(re.fullmatch(r'\d{8}', args.date), 'Date must be YYYYMMDD')
    raw = (ROOT / 'journal.json').read_bytes()
    rows = json.loads(raw)
    require(rows and [r['step'] for r in rows] == list(range(FIRST, FIRST + len(rows))), 'Journal is not the contiguous C1132 prefix')
    last = rows[-1]['step']
    require(last <= LAST and FIRST <= args.first <= last, 'Invalid report range')
    require(args.through is None or args.through == last, 'Current journal endpoint differs from --through')
    source_manifest = json.loads((ROOT / 'evidence/SOURCE_MANIFEST.json').read_text())
    require(source_manifest, 'Missing source manifest')
    for name, expected in source_manifest.items():
        require(Path(name).name == name, f'Unsafe snapshot name: {name}')
        require(sha((ROOT / 'evidence/sources' / name).read_bytes()) == expected, f'Source hash mismatch: {name}')
    from verify import verify_sources, verify_strategy_reviews
    _, _, _, _, inherited, predecessor_bindings = verify_sources(WORKSPACE, False)
    strategy_reviews = verify_strategy_reviews(rows)
    if last == LAST:
        verification = json.loads((ROOT / 'VERIFY.json').read_text())
        require(verification['status'] == 'PASS' and verification['first'] == FIRST and verification['last'] == LAST and verification['sequential_steps'] == STEP_COUNT and verification['final_300_step_verification'] is True, 'Final packaging requires the successful300-action VERIFY.json')
        require(verification['journal_sha256_at_read'] == sha(raw), 'Final verification does not bind the current journal')
        require(not (ROOT / 'pending.json').exists(), 'Final packet still has pending research')
        require(len(strategy_reviews) == 6 and verification['strategy_review_certificates'] == strategy_reviews, 'Final strategy reviews changed after verification')
    lines = [f'# 490d — C{args.first}–C{last}: sequential research record', '', f'Working continuation of C1131 · packet date{args.date}.', '',
             'Each completed step retains its question, declared inputs, exact results, finding, and reassessment. These are bounded research actions, not a count of independent discoveries. Canonical sources remain unchanged; second decimal inversion remains deferred.', '']
    for row in rows:
        if row['step'] < args.first:
            continue
        lines += [f'## C{row["step"]} — {row["title"]}', '', f'**Question.** {row["question"]}', '', f'**Sources.** {"; ".join(row["sources"])}', '', '**Inputs**', '', '```json', json.dumps(row['inputs'], indent=2, ensure_ascii=False), '```', '', '**Results**', '', '```json', json.dumps(row['results'], indent=2, ensure_ascii=False), '```', '', f'**Finding.** {row["finding"]}', '', f'**Reassessment.** {row["reassessment"]}', '']
    report_name = f'490d_C{args.first}_C{last}_Research_{args.date}.md'
    report_data = ('\n'.join(lines) + '\n').encode()
    (ROOT / report_name).write_bytes(report_data)
    (WORKSPACE / report_name).write_bytes(report_data)
    payloads = {}
    for path in sorted(ROOT.rglob('*')):
        if not path.is_file() or '__pycache__' in path.parts or path.name in {'MANIFEST.sha256', 'pending.json'}:
            continue
        match = re.fullmatch(r's(\d+)\.py', path.name)
        if match and int(match.group(1)) > last:
            continue
        payloads[str(path.relative_to(ROOT))] = path.read_bytes()
    require((ROOT / 'journal.json').read_bytes() == raw, 'Journal changed during packaging; retry between research steps')
    require(payloads['journal.json'] == raw, 'Captured journal differs from package input')
    manifest_data = ''.join(f'{sha(data)}  {name}\n' for name, data in sorted(payloads.items())).encode()
    (ROOT / 'MANIFEST.sha256').write_bytes(manifest_data)
    payloads['MANIFEST.sha256'] = manifest_data
    archive = WORKSPACE / f'490d_C1132_Through_C{last}_Evidence_{args.date}.zip'
    with zipfile.ZipFile(archive, 'w', zipfile.ZIP_DEFLATED) as handle:
        for name, data in sorted(payloads.items()):
            handle.writestr(name, data)
    print(json.dumps({'report': str(WORKSPACE / report_name), 'evidence': str(archive), 'completed_steps': len(rows), 'last_step': last, 'source_snapshots': len(source_manifest), 'inherited_inputs': len(inherited), 'predecessor_artifacts': len(predecessor_bindings), 'strategy_reviews': len(strategy_reviews), 'payloads': len(payloads), 'journal_sha256': sha(raw), 'zip_sha256': sha(archive.read_bytes())}, ensure_ascii=False))


if __name__ == '__main__':
    main()
