"""Remove only the five enumerated hertz field fixtures; retain proof artifacts."""
import base64
import json
import os
from pathlib import Path
import shutil
import subprocess

ROOT = Path(__file__).resolve().parent
INVENTORY = json.loads((ROOT / "FINAL-OWNED-INVENTORY.json").read_text())
HOME = Path(os.environ["LOCALAPPDATA"]) / "spt-core"
SPT = str(HOME / "bin" / "spt.exe")
ENV = {k: v for k, v in os.environ.items() if not k.startswith(("SPT_", "OWL_"))}
ENV["SPT_HOME"] = str(HOME)
RESULT = {"remote": None, "local": [], "status": "RUNNING"}


def native(label, argv, body=None):
    p = subprocess.run(argv, input=body, capture_output=True, timeout=120, env=ENV)
    (ROOT / (label + ".stdout")).write_bytes(p.stdout)
    (ROOT / (label + ".stderr")).write_bytes(p.stderr)
    if p.returncode:
        raise RuntimeError(label + " exit=" + str(p.returncode))
    return p.stdout


def main():
    # Refuse unrelated identities before doing anything destructive remotely.
    for fixture in INVENTORY:
        for endpoint in fixture["endpoints"]:
            info_path = HOME / "owlery" / endpoint / "info.json"
            if not info_path.exists():
                raise RuntimeError("MISSING_OWNED_PERCH:" + endpoint)
            info = json.loads(info_path.read_text(encoding="utf-8"))
            if info.get("adapter") != fixture["adapter"]:
                raise RuntimeError("FOREIGN_ADAPTER:" + endpoint)
            evidence = Path(fixture["evidence_dir"]) / "receivers" / endpoint
            evidence.mkdir(parents=True, exist_ok=True)
            ledger = info_path.parent / "helper-fetch.jsonl"
            if ledger.exists():
                shutil.copy2(ledger, evidence / "final-helper-fetch.jsonl")
    print("CLEANUP_READY ownership_checked", flush=True)
    payload = base64.b64encode(json.dumps(INVENTORY).encode()).decode()
    script = r"""
$ErrorActionPreference='Stop'; $ProgressPreference='SilentlyContinue'
Get-ChildItem Env: | Where-Object {$_.Name -like 'SPT_*' -or $_.Name -like 'OWL_*'} | Remove-Item
$fixtures = [Text.Encoding]::UTF8.GetString([Convert]::FromBase64String('__PAYLOAD__')) | ConvertFrom-Json
$spt = Join-Path $env:LOCALAPPDATA 'spt-core/bin/spt.exe'
$all = (& $spt serve list --json | Out-String | ConvertFrom-Json).entries
if($LASTEXITCODE -ne 0){throw 'SERVE_LIST_FAILED'}
$owned = @(); $removedFiles = @(); $removedRoots = @()
foreach($fixture in $fixtures){
  foreach($file in $fixture.owner_files){
    $item = Get-Item -LiteralPath $file.path -Force
    if($item.PSIsContainer -or ($item.Attributes -band [IO.FileAttributes]::ReparsePoint)){throw "UNEXPECTED_FILE_TYPE:$($file.path)"}
    if((Get-FileHash -Algorithm SHA256 -LiteralPath $file.path).Hash -ne $file.sha256){throw "FOREIGN_FILE_BYTES:$($file.path)"}
    foreach($entry in @($all | Where-Object {$_.path -eq $file.path})){
      if($entry.audience -notin $fixture.endpoints -or $entry.origin -notlike 'user-input:*'){throw "FOREIGN_SERVE_REFERENCE:$($entry.id)"}
      $owned += $entry
    }
  }
}
$removed = @()
foreach($entry in $owned){
  $out = & $spt serve rm $entry.id | Out-String
  if($LASTEXITCODE -ne 0){throw "SERVE_RM_FAILED:$($entry.id):$out"}
  $removed += $entry.id
}
$after = (& $spt serve list --json | Out-String | ConvertFrom-Json).entries
if($LASTEXITCODE -ne 0){throw 'SERVE_LIST_AFTER_FAILED'}
$ownedPaths = @($fixtures | ForEach-Object {$_.owner_files} | ForEach-Object {$_.path})
$remaining = @($after | Where-Object {$_.path -in $ownedPaths})
if($remaining.Count){throw 'OWNED_SERVE_REFERENCE_REMAINS'}
foreach($fixture in $fixtures){
  foreach($file in $fixture.owner_files){
    if((Get-FileHash -Algorithm SHA256 -LiteralPath $file.path).Hash -ne $file.sha256){throw "FILE_CHANGED_DURING_CLEANUP:$($file.path)"}
    Remove-Item -LiteralPath $file.path
    $removedFiles += $file.path
  }
  # No recursion: an unexpected new child must survive and fail cleanup.
  [IO.Directory]::Delete($fixture.owner_root, $false)
  $removedRoots += $fixture.owner_root
}
[ordered]@{before=$owned; removed_serve_ids=$removed; remaining_serve_entries=$remaining; removed_files=$removedFiles; removed_empty_roots=$removedRoots} | ConvertTo-Json -Depth 12 -Compress
""".replace("__PAYLOAD__", payload)
    bootstrap = "& ([scriptblock]::Create([Console]::In.ReadToEnd()))"
    remote = native("final-cleanup-remote", ["ssh", "-T", "-o", "BatchMode=yes", "-o", "ConnectTimeout=10", "decid@enlyzeam", "powershell.exe", "-NoProfile", "-NonInteractive", "-EncodedCommand", base64.b64encode(bootstrap.encode("utf-16le")).decode()], script.encode("utf-8"))
    RESULT["remote"] = json.loads(remote)
    for fixture in INVENTORY:
        for endpoint in fixture["endpoints"]:
            native("final-purge-" + endpoint, [SPT, "endpoint", "purge", endpoint, "--yes"])
            if (HOME / "owlery" / endpoint).exists():
                raise RuntimeError("PERCH_REMAINS:" + endpoint)
            RESULT["local"].append({"endpoint": endpoint, "purged": True})
        native("final-remove-" + fixture["adapter"], [SPT, "adapter", "remove", fixture["adapter"]])
        RESULT["local"].append({"adapter": fixture["adapter"], "soft_deregistered": True})
    RESULT["adapter_list_after"] = json.loads(native("final-adapter-list", [SPT, "adapter", "list", "--json"]))
    RESULT["status"] = "COMPLETE"


try:
    main()
except Exception as error:
    RESULT["status"] = "FAILED"
    RESULT["error"] = str(error)
finally:
    (ROOT / "FINAL-CLEANUP.json").write_text(json.dumps(RESULT, indent=2), encoding="utf-8")
    print("CLEANUP_RESULT " + RESULT["status"], flush=True)
raise SystemExit(0 if RESULT["status"] == "COMPLETE" else 1)
