from unittest import TestCase
from unittest.mock import patch

from sohstationviewer.controller.util import (
    check_chan,
    check_wf_chan,
    check_soh_chan
)


class TestCheckChan(TestCase):
    def setUp(self) -> None:
        self.req_soh_chans = ['LCE', 'LCQ']
        self.req_wf_chans = ['LHE', 'HHE']

        check_soh_chan_patcher = patch(
            'sohstationviewer.controller.util.check_soh_chan',
            wraps=check_soh_chan
        )
        self.addCleanup(check_soh_chan_patcher.stop)
        self.mock_check_soh_chan = check_soh_chan_patcher.start()

        check_wf_chan_patcher = patch(
            'sohstationviewer.controller.util.check_wf_chan',
            wraps=check_wf_chan
        )
        self.addCleanup(check_wf_chan_patcher.stop)
        self.mock_check_wf_chan = check_wf_chan_patcher.start()

    def test_channel_is_waveform_and_is_requested(self):
        waveform_channel = 'LHE'
        ret = check_chan(waveform_channel, self.req_soh_chans,
                         self.req_wf_chans, True, True)
        self.assertEqual(ret, 'WF')
        self.assertTrue(self.mock_check_wf_chan.called)

    def test_channel_is_waveform_but_not_requested(self):
        waveform_channel = 'HH1'
        ret = check_chan(waveform_channel, self.req_soh_chans,
                         self.req_wf_chans, True, True)
        self.assertFalse(ret)
        self.assertTrue(self.mock_check_wf_chan.called)

    def test_channel_is_soh_and_is_requested(self):
        soh_channel = 'LCE'
        ret = check_chan(
            soh_channel, self.req_soh_chans, self.req_wf_chans, True, True)
        self.assertEqual(ret, 'SOH')
        self.assertTrue(self.mock_check_soh_chan.called)

    def test_channel_is_soh_but_not_requested(self):
        soh_channel = 'VKI'
        ret = check_chan(soh_channel, self.req_soh_chans, self.req_wf_chans,
                         True, True)
        self.assertFalse(ret)
        self.assertTrue(self.mock_check_soh_chan.called)

    def test_channel_is_mass_position(self):
        with self.subTest('test_mass_position_is_requested'):
            mass_pos_channel = 'VM1'
            ret = check_chan(mass_pos_channel, self.req_soh_chans,
                             self.req_wf_chans, True, False)
            self.assertEqual(ret, 'MP')
            self.assertFalse(self.mock_check_soh_chan.called)
        self.mock_check_soh_chan.reset_mock()

        with self.subTest('test_mass_position_is_not_requested'):
            mass_pos_channel = 'VM1'
            ret = check_chan(mass_pos_channel, self.req_soh_chans,
                             self.req_wf_chans, False, True)
            self.assertFalse(ret)
            self.assertFalse(self.mock_check_soh_chan.called)


class TestCheckSohChan(TestCase):
    def setUp(self) -> None:
        self.req_soh_chans = ['LCE', 'LCQ', 'EX?']
        self.sample_channel_ids = ['ODV', 'QGA', 'NF4', 'OLY', 'UZM']

    def test_all_channels_requested(self):
        self.req_soh_chans = []

        for channel_id in self.sample_channel_ids:
            self.assertTrue(check_soh_chan(channel_id, self.req_soh_chans))

    def test_channel_is_requested(self):
        with self.subTest('test_normal_channels'):
            channel_id = 'LCE'
            self.assertTrue(check_soh_chan(channel_id, self.req_soh_chans))
        with self.subTest('test_mass_position_channels'):
            base_channel_id = 'VM'
            channel_suffixes = ['0', '1', '2', '3', '4', '5', '6']
            for suffix in channel_suffixes:
                channel_id = base_channel_id + suffix
                self.assertTrue(check_soh_chan(channel_id, self.req_soh_chans))
        with self.subTest('test_external_soh_channels'):
            base_channel_id = 'EX'
            channel_suffixes = ['1', '2', '3']
            for suffix in channel_suffixes:
                channel_id = base_channel_id + suffix
                self.assertTrue(check_soh_chan(channel_id, self.req_soh_chans))

    def test_channel_not_requested(self):
        for channel_id in self.sample_channel_ids:
            self.assertFalse(check_soh_chan(channel_id, self.req_soh_chans))


class TestCheckWfChan(TestCase):
    def test_channel_is_requested(self):
        req_wf_chans = ['LHE', 'HHE']
        channel_id = 'LHE'
        self.assertTupleEqual(
            check_wf_chan(channel_id, req_wf_chans),
            ('WF', True)
        )

    def test_channel_not_requested(self):
        req_wf_chans = ['LHE', 'HHE']
        with self.subTest('test_waveform_channel'):
            channel_id = 'AHE'
            self.assertTupleEqual(
                check_wf_chan(channel_id, req_wf_chans),
                ('WF', False)
            )
        with self.subTest('test_non_waveform_channel'):
            channel_id = 'Not a waveform channel'
            self.assertTupleEqual(
                check_wf_chan(channel_id, req_wf_chans),
                ('', False)
            )

    def test_len1_wildcard_request(self):
        req_wf_chans = ['*']
        sample_channel_ids = ['LHE', 'HHE', 'AL2', 'MNZ', 'VNN']
        with self.subTest('test_waveform_channel'):
            for channel_id in sample_channel_ids:
                self.assertTupleEqual(
                    check_wf_chan(channel_id, req_wf_chans),
                    ('WF', True)
                )
        with self.subTest('test_non_waveform_channel'):
            channel_id = 'Not a waveform channel'
            self.assertTupleEqual(
                check_wf_chan(channel_id, req_wf_chans),
                ('', False)
            )

    def test_len2_wildcard_request(self):
        req_wf_chans = ['H*']
        with self.subTest('Requested start char'):
            channel_id = 'HHE'
            self.assertTupleEqual(
                check_wf_chan(channel_id, req_wf_chans),
                ('WF', True)
            )
        with self.subTest('None-requested start char'):
            channel_id = 'LHE'
            self.assertTupleEqual(
                check_wf_chan(channel_id, req_wf_chans),
                ('WF', False)
            )

        req_wf_chans = ['*E']
        with self.subTest('Requested end char'):
            channel_id = 'HHE'
            self.assertTupleEqual(
                check_wf_chan(channel_id, req_wf_chans),
                ('WF', True)
            )
        with self.subTest('None-requested end char'):
            channel_id = 'LHN'
            self.assertTupleEqual(
                check_wf_chan(channel_id, req_wf_chans),
                ('WF', False)
            )

    def test_len3_wildcard_request(self):
        req_wf_chans = ['HH*']
        with self.subTest('Requested start 2 chars'):
            channel_id = 'HHE'
            self.assertTupleEqual(
                check_wf_chan(channel_id, req_wf_chans),
                ('WF', True)
            )
        with self.subTest('None-requested start 2 chars'):
            channel_id = 'LHE'
            ret = check_wf_chan(channel_id, req_wf_chans)
            self.assertTupleEqual(
                ret,
                ('WF', False)
            )

        req_wf_chans = ['H*E']
        with self.subTest('Requested start or end char'):
            channel_id = 'HHE'
            self.assertTupleEqual(
                check_wf_chan(channel_id, req_wf_chans),
                ('WF', True)
            )
        with self.subTest('None-requested start or end char'):
            channel_id = 'LHN'
            self.assertTupleEqual(
                check_wf_chan(channel_id, req_wf_chans),
                ('WF', False)
            )

        req_wf_chans = ['*HE']
        with self.subTest('Requested 2 end chars'):
            channel_id = 'HHE'
            self.assertTupleEqual(
                check_wf_chan(channel_id, req_wf_chans),
                ('WF', True)
            )
        with self.subTest('None-requested 2 end chars'):
            channel_id = 'LHN'
            self.assertTupleEqual(
                check_wf_chan(channel_id, req_wf_chans),
                ('WF', False)
            )