import io
import unittest
from unittest.mock import patch
import build_parallel_queue as queue


class ParallelQueueTest(unittest.TestCase):
    def rows(self, claims='', contracts=None, coverage=None):
        contracts = contracts or [
            dict(repo='store', method='POST', path='/p/Article/info'),
            dict(repo='store', method='POST', path='/p/article/update'),
            dict(repo='ai_api', method='*', path='/api/User/list'),
            dict(repo='unreviewed', method='GET', path='/unknown')]
        if coverage is None:
            coverage = [dict(repo=r['repo'], method=r['method'], kind='http',
                             route_or_command=r['path']) for r in contracts]
        text = 'batch,owner,repo,method,path,state,scope\n' + claims
        with patch.object(queue.base, 'read_csv', side_effect=[([], contracts, b''), ([], coverage, b'')]), \
                patch.object(queue.Path, 'open', return_value=io.StringIO(text)):
            return queue.records()

    def test_every_key_including_unreviewed_has_one_owner(self):
        rows, active = self.rows('261,review_equipment237,store,POST,/p/article/info,running,own\n')
        self.assertEqual((len(rows), active), (4, 1))
        self.assertEqual({r['owner'] for r in rows if r['repo'] == 'store'}, {'review_equipment237'})
        self.assertEqual([r['owner'] for r in rows if r['repo'] == 'unreviewed'], ['root-inventory-triage'])
        self.assertEqual(len({(r['repo'], r['method'], r['path']) for r in rows}), 4)

    def test_duplicate_case_variant_claim_rejected(self):
        with self.assertRaisesRegex(ValueError, 'Duplicate'):
            self.rows('1,a,store,POST,/p/Article/info,running,x\n2,b,store,POST,/p/article/info,queued,x\n')

    def test_wildcard_overlap_rejected(self):
        with self.assertRaisesRegex(ValueError, 'Wildcard'):
            self.rows('1,a,ai_api,*,/api/user/list,running,x\n2,a,ai_api,GET,/api/user/list,queued,x\n')

    def test_controller_cannot_be_split_between_workers(self):
        with self.assertRaisesRegex(ValueError, 'Controller'):
            self.rows('1,a,store,POST,/p/article/info,running,x\n2,b,store,POST,/p/article/update,queued,x\n')

    def test_unknown_claim_rejected(self):
        with self.assertRaisesRegex(ValueError, 'absent'):
            self.rows('1,a,store,POST,/p/missing/info,running,x\n')

    def test_missing_source_key_rejected(self):
        with self.assertRaisesRegex(ValueError, 'keys differ'):
            self.rows(coverage=[])

    def test_completed_claim_not_active(self):
        rows, count = self.rows('1,a,store,POST,/p/article/info,reviewed,x\n')
        self.assertEqual(count, 0)
        self.assertTrue(all(not r['active_batches'] for r in rows))


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