import importlib.util
import json
from pathlib import Path
import unittest
from unittest.mock import Mock

spec = importlib.util.spec_from_file_location('reader_example', Path(__file__).resolve().parents[1] / 'docs/integration/metadata_reader_example.py')
example = importlib.util.module_from_spec(spec)
spec.loader.exec_module(example)


class ReaderExampleTest(unittest.TestCase):
    def setUp(self):
        self.client = Mock()
        self.frames, self.clears = [], []
        self.reader = example.FrameReader(self.client, 'demo', 'ns', self.frames.append, self.clears.append)
        self.status = dict(cameraId='demo', streamKey=self.reader.stream_key, state='RUNNING', runId='r1', runGeneration=1)
        self.client.get.side_effect = lambda _: json.dumps(self.status)
        self.client.hget.return_value = self.reader.stream_key

    def entries(self, seqs, run='r1'):
        return [(self.reader.stream_key, [(str(i)+'-0', {'json':json.dumps(dict(schemaVersion='1', sourceId='demo', runId=run,
            runGeneration=1, frameSeq=i, objects=[]))}) for i in seqs])]

    def test_cursor_duplicates_empty_objects_and_new_run(self):
        self.client.xread.return_value = self.entries([1, 1, 2])
        self.assertEqual(self.reader.poll(), 2)
        self.assertEqual(self.frames[-1]['objects'], [])
        self.assertEqual(self.reader.cursor, '2-0')
        self.status['runId'] = 'r2'
        self.client.xread.return_value = self.entries([0], 'r2')
        self.assertEqual(self.reader.poll(), 1)
        self.assertEqual(self.reader.last_seq, 0)
        self.assertEqual(self.client.xread.call_args.args[0], {self.reader.stream_key:'0-0'})

    def test_stopped_never_reads_frames(self):
        self.status['state'] = 'STOPPED'
        self.assertEqual(self.reader.poll(), 0)
        self.client.xread.assert_not_called()
        self.assertEqual(self.clears, ['STOPPED'])

    def test_stop_during_read_discards_batch(self):
        before = json.dumps(self.status)
        self.status['state'] = 'STOPPED'
        self.client.get.side_effect = [before, json.dumps(self.status)]
        self.client.xread.return_value = self.entries([1])
        self.assertEqual(self.reader.poll(), 0)
        self.assertFalse(self.frames)

    def test_expired_frames_clear_display(self):
        self.client.xread.return_value = []
        self.client.exists.return_value = False
        self.reader.poll()
        self.assertIn('FRAME_DATA_EXPIRED', self.clears)


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