#!/usr/bin/env python3
"""Local text/hash checks only: never invokes Docker, Java, Gradle, or a device."""
import hashlib
import json
from pathlib import Path
import re
import sys

ALLOWED_GRADLE_ARGS = {
    'help', 'tasks', '--version', ':app:testDebugUnitTest', ':app:assembleDebug',
    '--stacktrace', '--info', '--offline',
}
TEST_FILTER = re.compile(r'com\.cpt\.zhct\.weighting\.(hardware|antiescape|session|diagnostics)\.[A-Za-z0-9_.*$]+')


def has_evidence(value):
    if isinstance(value, str):
        return bool(value.strip())
    if isinstance(value, dict):
        return any(has_evidence(item) for item in value.values())
    if isinstance(value, list):
        return any(has_evidence(item) for item in value)
    return False


def check_review(path):
    try:
        decision = json.loads(path.read_text())
    except (OSError, ValueError) as error:
        raise SystemExit(f'REVIEW BLOCKED: cannot read {path}: {error}')
    if not isinstance(decision, dict) or decision.get('status') != 'APPROVED':
        raise SystemExit('REVIEW BLOCKED: overall plan awaits user review; no Docker build/run or Java execution performed.')
    if not has_evidence(decision.get('approval_evidence')):
        raise SystemExit('REVIEW BLOCKED: APPROVED requires nonempty evidence of the real user approval; status alone is insufficient.')


def check_gradle_args(arguments):
    if not arguments:
        raise SystemExit('Pass local Gradle tasks after --')
    waiting_for_filter = False
    has_filter = False
    for arg in arguments:
        if waiting_for_filter:
            if not TEST_FILTER.fullmatch(arg):
                raise SystemExit('Invalid --tests pattern: use the hardware, antiescape, session or diagnostics package prefix.')
            waiting_for_filter = False
            continue
        if arg == '--tests':
            waiting_for_filter = True
            has_filter = True
        elif arg not in ALLOWED_GRADLE_ARGS:
            raise SystemExit('Gradle argument is outside this reviewed local-build scope: ' + arg)
    if waiting_for_filter:
        raise SystemExit('Missing pattern after --tests')
    if has_filter and ':app:testDebugUnitTest' not in arguments:
        raise SystemExit('--tests requires the approved :app:testDebugUnitTest task')


def source_snapshot(root):
    # Re-enumerate each time: detect additions/deletions and edits to an already-dirty file.
    paths = [root / 'build.gradle', root / 'app/build.gradle',
             root / 'gradle/wrapper/gradle-wrapper.properties']
    paths += list((root / 'app/src').rglob('*.java'))
    paths += list((root / 'app/libs').glob('*.aar'))
    return {str(p.relative_to(root)): hashlib.sha256(p.read_bytes()).hexdigest()
            for p in sorted(paths) if p.is_file()}


def main():
    if len(sys.argv) < 2:
        raise SystemExit('Usage: runner-checks.py review FILE | gradle-args ARGS... | snapshot ROOT OUTPUT')
    action = sys.argv[1]
    if action == 'review' and len(sys.argv) == 3:
        check_review(Path(sys.argv[2]))
    elif action == 'gradle-args':
        check_gradle_args(sys.argv[2:])
    elif action == 'snapshot' and len(sys.argv) == 4:
        result = source_snapshot(Path(sys.argv[2]))
        Path(sys.argv[3]).write_text(json.dumps(result, indent=2) + '\n')
    else:
        raise SystemExit('Invalid local-check arguments')


if __name__ == '__main__':
    main()
