import json
import subprocess
import unittest
from pathlib import Path
from unittest.mock import patch
import rcms, operations as ops, recover_20260821 as rescue, test_operations

class Rescue(unittest.TestCase):
    setUp=test_operations.Operations.setUp

    def test_replaces_only_posts_and_is_idempotent(self):
        self.cfg['runs_root']=str(self.root/'runs')
        self.cfg['slurm']={m:{'nodes':1,'tasks_per_node':1} for m in ops.MODEL_NAMES}
        rcms.put(self.root/'config.json',self.cfg)
        for model in rescue.JOBS:
            (Path(self.cfg['legacy_dirs'][model])/'wdir'/self.cycle/'output').mkdir(parents=True)
        run=self.root/'runs'/self.cycle/'attempt';run.mkdir(parents=True)
        man={'models':list(rescue.JOBS),'config':self.cfg,'cycle':self.cycle}
        submitted=[];cancelled=[]
        rows={job:{} for pair in rescue.JOBS.values() for job in pair}
        def submit(root,manifest,model,phase,token,dependency,dependency_type):
            submitted.append((model,phase,dependency,dependency_type))
            rcms.put(root/(model+'-post-rescue.job.json'),{'job_id':'999'+str(len(submitted))})
        def cancel(cmd):
            self.assertEqual(cmd[0],'scancel');cancelled.append(cmd[1]);rows.pop(cmd[1])
            return subprocess.CompletedProcess(cmd,0)
        with patch.object(rcms,'HERE',self.root),patch.object(rescue,'check_job',return_value={'JobState':'PENDING'}),patch.object(ops,'queue',side_effect=lambda cfg:dict(rows)),patch.object(ops,'write_preflight'),patch.object(rcms,'validate_config'),patch.object(ops,'new_run',return_value=(run,man)),patch.object(ops,'managed_run',return_value=(run,man)),patch.object(rcms,'submit_job',side_effect=submit),patch.object(subprocess,'run',side_effect=cancel),patch('sys.argv',['recover','--execute']):
            rescue.main();rescue.main()
        self.assertEqual(submitted,[('wrf','post','1401038','afterany'),('regcm','post','1401040','afterany')])
        self.assertEqual(cancelled,['1401039','1401041'])

    def test_job_identity_must_match(self):
        row='JobId=1401038 UserId=other(9) JobName=rcms-wrf-2026082100-integrate-initial JobState=RUNNING'
        with patch.object(subprocess,'run',return_value=subprocess.CompletedProcess([],0,row,'')):
            with self.assertRaisesRegex(RuntimeError,'owner'):
                rescue.check_job('1401038','wrf','integrate')

if __name__=='__main__':unittest.main(verbosity=2)
