from itertools import chain
from unittest.case import TestCase
from uuid import uuid4

from eventsourcing.application import LocalNotificationLog
from eventsourcing.persistence import StoredEvent
from eventsourcing.sqlite import SQLiteDatastore, SQLiteProcessRecorder
from eventsourcing.system import NotificationLogReader


class TestNotificationLogReader(TestCase):
    def test_read(self):
        recorder = SQLiteProcessRecorder(SQLiteDatastore(":memory:"))
        recorder.create_table()

        # Construct notification log.
        notification_log = LocalNotificationLog(recorder, section_size=5)
        reader = NotificationLogReader(notification_log, section_size=10)
        notifications = list(reader.read(start=1))
        self.assertEqual(len(notifications), 0)

        # Write 5 events.
        originator_id = uuid4()
        for i in range(5):
            stored_event = StoredEvent(
                originator_id=originator_id,
                originator_version=i,
                topic="topic",
                state=b"state",
            )
            recorder.insert_events(
                [stored_event],
            )

        notifications = list(reader.read(start=1))
        self.assertEqual(len(notifications), 5)

        # Write 4 events.
        originator_id = uuid4()
        for i in range(4):
            stored_event = StoredEvent(
                originator_id=originator_id,
                originator_version=i,
                topic="topic",
                state=b"state",
            )
            recorder.insert_events([stored_event])

        notifications = list(reader.read(start=1))
        self.assertEqual(len(notifications), 9)

        notifications = list(reader.read(start=2))
        self.assertEqual(len(notifications), 8)

        notifications = list(reader.read(start=3))
        self.assertEqual(len(notifications), 7)

        notifications = list(reader.read(start=4))
        self.assertEqual(len(notifications), 6)

        notifications = list(reader.read(start=8))
        self.assertEqual(len(notifications), 2)

        notifications = list(reader.read(start=9))
        self.assertEqual(len(notifications), 1)

        notifications = list(reader.read(start=10))
        self.assertEqual(len(notifications), 0)

    def test_select(self):
        recorder = SQLiteProcessRecorder(SQLiteDatastore(":memory:"))
        recorder.create_table()

        # Construct notification log.
        notification_log = LocalNotificationLog(recorder, section_size=5)
        reader = NotificationLogReader(notification_log, section_size=5)
        notifications = list(chain(*reader.select(start=1)))
        self.assertEqual(len(notifications), 0)

        # Write 5 events.
        originator_id = uuid4()
        for i in range(5):
            stored_event = StoredEvent(
                originator_id=originator_id,
                originator_version=i,
                topic="topic",
                state=b"state",
            )
            recorder.insert_events(
                [stored_event],
            )

        notifications = list(chain(*reader.select(start=1)))
        self.assertEqual(len(notifications), 5)

        # Write 4 events.
        originator_id = uuid4()
        for i in range(4):
            stored_event = StoredEvent(
                originator_id=originator_id,
                originator_version=i,
                topic="topic",
                state=b"state",
            )
            recorder.insert_events([stored_event])

        notifications = list(chain(*reader.select(start=1)))
        self.assertEqual(len(notifications), 9)

        notifications = list(chain(*reader.select(start=2)))
        self.assertEqual(len(notifications), 8)

        notifications = list(chain(*reader.select(start=3)))
        self.assertEqual(len(notifications), 7)

        notifications = list(chain(*reader.select(start=4)))
        self.assertEqual(len(notifications), 6)

        notifications = list(chain(*reader.select(start=8)))
        self.assertEqual(len(notifications), 2)

        notifications = list(chain(*reader.select(start=9)))
        self.assertEqual(len(notifications), 1)

        notifications = list(chain(*reader.select(start=10)))
        self.assertEqual(len(notifications), 0)
