#!/usr/bin/env python3
"""NBYJXOF3 classification only; this script never deletes or moves a target."""
import datetime
import hashlib
import json
import os
from pathlib import Path
import shutil
import stat
import subprocess

ROOT = Path('/home/reavus/projects/spt-core/spt-core')
TARGET = ROOT / '.worktrees/consumer-linux-304-b8482445/target'
OLD_PROOF = ROOT / '.spt/preserved/304-handoff/consumer-linux'
PROOF = ROOT / '.spt/preserved/308-registry-process-lock/linux-validation'
prefix = str(TARGET) + '/'
metadata = TARGET.lstat()
assert stat.S_ISDIR(metadata.st_mode) and not TARGET.is_symlink(), 'target is not the expected real directory'
assert TARGET.resolve() == TARGET, 'target resolves elsewhere'
owner = json.loads((TARGET / 'POOL-OWNER.json').read_text())
assert owner['owner_tree'] == str(TARGET.parent)
assert set(owner) <= {'owner_tree', 'written_by'}, 'pool has a claim or unclassified metadata'
proof_hashes = {}
for directory, _, files in os.walk(OLD_PROOF):
    for name in files:
        path = Path(directory) / name
        assert not path.is_symlink(), path
        proof_hashes[str(path.relative_to(OLD_PROOF))] = hashlib.sha256(path.read_bytes()).hexdigest()
release = json.loads((OLD_PROOF / 'attempt3/pool-release-receipt.json').read_text())
assert release['exit'] == 0
assert proof_hashes['attempt3/pool-release.log'] == release['log_sha256']
for phase in ('phase-a', 'phase-b'):
    receipt = json.loads((OLD_PROOF / ('attempt3/' + phase + '-receipt.json')).read_text())
    assert receipt['exit'] == 0
    assert proof_hashes['attempt3/' + phase + '.log'] == receipt['log_sha256']
creation = (PROOF / 'old-lane-creation.txt').read_text()
assert "Preparing worktree (checking out 'todlando/304-linux-b8482445')" in creation
claim = json.loads((OLD_PROOF / 'attempt2/pool-claim-receipt.json').read_text())
assert 'todlando-304-linux-b8482445' in claim['command']

inbound = []
walk_errors = []
for directory, dirs, files in os.walk('/home/reavus', followlinks=False, onerror=lambda e: walk_errors.append(str(e))):
    # Internal links disappear with their own subtree; only EXTERNAL inbound
    # references matter. Do not traverse the deletion candidate at all.
    dirs[:] = [name for name in dirs if Path(directory) / name != TARGET]
    for name in dirs + files:
        path = Path(directory) / name
        if not path.is_symlink():
            continue
        resolved = os.path.realpath(path)
        if resolved == str(TARGET) or resolved.startswith(prefix):
            inbound.append({'path': str(path), 'resolved': resolved})

active = []
references = []
permissions = []
for proc in Path('/proc').iterdir():
    if not proc.name.isdigit():
        continue
    try:
        name = (proc / 'comm').read_text().strip()
        command = (proc / 'cmdline').read_bytes().replace(b'\0', b' ').decode(errors='replace')
        executable = None
        try:
            executable = os.readlink(proc / 'exe')
        except PermissionError:
            permissions.append({'pid': int(proc.name), 'field': 'exe'})
        except FileNotFoundError:
            pass
        if any(word in name for word in ('cargo', 'rustc', 'nextest', 'Runner.Worker')) or executable and '/deps/' in executable:
            active.append({'pid': int(proc.name), 'name': name, 'exe': executable, 'command': command})
        if executable and executable.startswith(prefix) or str(TARGET) in command:
            references.append({'pid': int(proc.name), 'kind': 'exe-or-command', 'exe': executable, 'command': command})
        for field in ('cwd', 'root'):
            try:
                value = os.readlink(proc / field)
                if value == str(TARGET) or value.startswith(prefix):
                    references.append({'pid': int(proc.name), 'kind': field, 'path': value})
            except PermissionError:
                permissions.append({'pid': int(proc.name), 'field': field})
            except FileNotFoundError:
                pass
        try:
            for fd in (proc / 'fd').iterdir():
                try:
                    value = os.readlink(fd)
                    if value == str(TARGET) or value.startswith(prefix):
                        references.append({'pid': int(proc.name), 'kind': 'fd', 'path': value})
                except FileNotFoundError:
                    pass
        except PermissionError:
            permissions.append({'pid': int(proc.name), 'field': 'fd'})
        try:
            if str(TARGET) in (proc / 'maps').read_text():
                references.append({'pid': int(proc.name), 'kind': 'maps'})
        except PermissionError:
            permissions.append({'pid': int(proc.name), 'field': 'maps'})
    except (FileNotFoundError, ProcessLookupError):
        continue
    except PermissionError:
        permissions.append({'pid': int(proc.name), 'field': 'process'})

size = int(subprocess.check_output(['du', '-s', '-B1', str(TARGET)], text=True).split()[0])
apparent = int(subprocess.check_output(['du', '-s', '-b', str(TARGET)], text=True).split()[0])
report = {'utc': datetime.datetime.now(datetime.timezone.utc).isoformat(), 'authority': 'NBYJXOF3',
          'target': str(TARGET), 'outbound': 'real-directory', 'device': metadata.st_dev, 'inode': metadata.st_ino,
          'owner': owner, 'creation_evidence': creation, 'lane_label': 'todlando-304-linux-b8482445',
          'preserved_proof_root': str(OLD_PROOF), 'proof_sha256': proof_hashes,
          'last_release': release, 'inbound_scope': '/home/reavus', 'inbound': inbound, 'walk_errors': walk_errors,
          'active_producers': active, 'target_process_references': references,
          'process_permission_limits': permissions, 'allocated_bytes': size, 'apparent_bytes': apparent,
          'free_bytes': shutil.disk_usage(ROOT).free, 'target_deleted': False}
(PROOF / 'old-target-classification.json').write_text(json.dumps(report, indent=2) + '\n')
print(json.dumps({key: value for key, value in report.items() if key not in ('proof_sha256', 'process_permission_limits')}, indent=2))
print('PROOF_FILES', len(proof_hashes), 'PROCESS_PERMISSION_LIMITS', len(permissions))
assert not inbound and not walk_errors and not active and not references, 'reclaim prerequisite failed'
