from pathlib import Path
import json, datetime, shutil, urllib.request, subprocess, importlib.util, os
root=Path('/opt/charter-live/live_deploy_v2')
source=root/'v2_stats_dashboard.py'
queue_path=root/'v2_classification_review_queue.json'
stamp=datetime.datetime.now(datetime.timezone.utc).isoformat()
backup=Path('/opt/charter-live/backups/clear_v2_review_'+datetime.datetime.now().strftime('%Y%m%d_%H%M%S'))
with urllib.request.urlopen('http://127.0.0.1:5511/json',timeout=90) as response: data=json.load(response)
queue=json.loads(queue_path.read_text()) if queue_path.exists() else []
rows=data.get('unclassified_trades',[])
ids={str(row.get('order_id') or '').strip() for row in rows}-{''}
backup.mkdir(parents=True)
shutil.copy2(source,backup/source.name)
if queue_path.exists():shutil.copy2(queue_path,backup/queue_path.name)
shutil.copy2('/etc/systemd/system/charter-v2-stats-dashboard.service',backup/'charter-v2-stats-dashboard.service')
(backup/'current_unclassified.json').write_text(json.dumps(rows,indent=2))
old=source.read_text()
helper='''def _archived_review_order_ids():
    """Current cases cleared by the operator; new order IDs remain visible."""
    return {
        str(item.get("order_id") or "").strip()
        for item in _load_review_queue()
        if item.get("status") == "archived"
        and item.get("action") == "clear_review"
    }


'''
assert 'def _archived_review_order_ids' not in old
new=old.replace('def _certification_candidates(data):',helper+'def _certification_candidates(data):',1)
new=new.replace('    rejected = _rejected_order_ids()\n    candidates = []','    rejected = _rejected_order_ids()\n    archived = _archived_review_order_ids()\n    candidates = []')
assert new.count('    archived = _archived_review_order_ids()')==2
new=new.replace('if not order_id or order_id in rejected:', 'if not order_id or order_id in rejected or order_id in archived:',1)
new=new.replace('if order_id and order_id in rejected:', 'if order_id and order_id in rejected and order_id not in archived:',1)
compile(new,str(source),'exec')
pending=0
for item in queue:
 if item.get('status')=='pending':
  item.update(status='archived',resolved_at=stamp,archive_reason='User requested clearing current review entries')
  pending+=1
for row in rows:
 oid=str(row.get('order_id') or '').strip()
 if oid:
  queue.append(dict(proposal_id='clear-'+oid,created_at=stamp,resolved_at=stamp,status='archived',action='clear_review',order_id=oid,trade_snapshot=row,reason='User requested clearing current review entries; classification unchanged'))
def atomic(path,content):
 tmp=path.with_suffix(path.suffix+'.clear-tmp')
 tmp.write_text(content)
 os.chmod(tmp,path.stat().st_mode & 0o777 if path.exists() else 0o600)
 os.replace(tmp,path)
try:
 atomic(queue_path,json.dumps(queue,ensure_ascii=False,indent=2))
 atomic(source,new)
 spec=importlib.util.spec_from_file_location('verify_dash',source)
 module=importlib.util.module_from_spec(spec);spec.loader.exec_module(module)
 assert module._certification_candidates(data)==[]
 assert module._review_candidates(data)==[]
 assert not [x for x in module._load_review_queue() if x.get('status')=='pending']
 if rows:
  future=dict(rows[0],order_id='verification-new-order-only-in-memory')
  assert len(module._certification_candidates(dict(data,unclassified_trades=[future])))==1
 subprocess.run(['systemctl','restart','charter-v2-stats-dashboard'],check=True)
except Exception:
 shutil.copy2(backup/source.name,source)
 if (backup/queue_path.name).exists():shutil.copy2(backup/queue_path.name,queue_path)
 subprocess.run(['systemctl','restart','charter-v2-stats-dashboard'])
 raise
print(json.dumps(dict(archived_cases=len(ids),archived_pending_proposals=pending,backup=str(backup))))
