import unittest
from pathlib import Path
from unittest.mock import patch
import rcms, operations, recovery, test_operations

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

    def test_relative_storage_frozen_for_runtime(self):
        self.cfg['runs_root']='test-results/'+self.root.name+'/runs'
        self.cfg['slurm']={m:{'nodes':1,'tasks_per_node':1} for m in operations.MODEL_NAMES}
        expected=rcms.HERE/self.cfg['runs_root']
        with patch.object(rcms,'validate_config'),patch.object(rcms,'inventory',return_value=('2026082106',[])):
            root,man=operations.new_run(self.cfg,self.cycle,['wrf'])
        self.assertEqual(root.parent.parent,expected)
        with patch.object(rcms,'HERE',root/'runtime'):
            self.assertEqual(operations.storage(man['config']),expected)

    def test_rescue_rejects_truncated_output(self):
        raw=self.root/'raw';raw.mkdir()
        for t in ('00','06'):
            rcms.put(raw/('wrfout_d01_2026-08-21_'+t+':00:00'),'data')
        rcms.put(raw/'wrfxtrm_d01_fixture','data')
        class Reader:
            def nc(self,p):return ''
            def run(self,args):return Path(args[-1]).name[len('wrfout_d01_'):]
        man={'cycle':self.cycle,'recovery':{'wrf':{'expected_end':'2027030100'}}}
        with self.assertRaisesRegex(RuntimeError,'required end'):
            recovery.validate_raw(man,'wrf',raw,Reader())
        man['recovery']['wrf']['expected_end']='2026082106'
        self.assertEqual(recovery.validate_raw(man,'wrf',raw,Reader())['end'],'2026082106')

    def test_wrf_runtime_separate_from_output(self):
        work=self.root/'integration';work.mkdir()
        model=self.root/'installed/run';model.mkdir(parents=True)
        rcms.put(model/'CAMtr_volume_mixing_ratio.RCP4.5','table')
        self.cfg['wrf_dir']=str(model.parent)
        source=self.root/'wrf/wdir'/self.cycle;source.mkdir()
        for t in ('00','06'):
            rcms.put(source/('met_em.d01.2026-08-21_'+t+':00:00.nc'),'input')
        man={'config':self.cfg,'cycle':self.cycle,'end':'2026082106','tasks':{'wrf':40},
             'recovery':{'wrf':{'action':'RESUME','work':str(source)}}}
        calls=[]
        class Reader:
            def nc(self,p):return ''
            def run(self,args,cwd=None):
                if 'mpirun' in args:
                    calls.append(cwd)
                    if str(args[-1]).endswith('real.exe'):
                        rcms.put(cwd/'rsl.error.0000','SUCCESS COMPLETE REAL')
                        for n in ('wrfinput_d01','wrfbdy_d01','wrflowinp_d01'):rcms.put(cwd/n,'input')
                    else:
                        rcms.put(cwd/'rsl.error.0000','SUCCESS COMPLETE WRF')
                        rcms.put(cwd/'output/wrfout_d01_2026-08-21_06:00:00','output')
                return '2026-08-21_06:00:00'
        with patch.object(recovery,'check_met',return_value='38'):
            result=rcms.wrf_from_met(man,work,Reader(),source)
        self.assertEqual(calls,[work/'real',work/'wrf'])
        raw=Path(result['raw'])
        self.assertEqual(raw,source/'output')
        self.assertFalse((raw/'rsl.error.0000').exists())
        self.assertFalse((raw/'namelist.input').exists())
        self.assertTrue((work/'wrf/rsl.error.0000').is_file())
        nml=(work/'wrf/namelist.input').read_text()
        for name in ('wrfout','wrfrst','wrfxtrm'):
            self.assertIn('output/'+name+'_d<domain>_<date>',nml)

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