"""Unit tests for attendance processor."""

import unittest
from datetime import datetime
from attendance_app.processor import AttendanceProcessor
from attendance_app.database import MockUserDatabase


class TestAttendanceProcessor(unittest.TestCase):
    """Test AttendanceProcessor class."""

    def setUp(self):
        """Set up test fixtures."""
        # Mock user database
        self.mock_users = {
            'user123': ('S001', 'Taro Yamada', 'ヤマダ タロウ', 'CS', '01'),
            'user456': ('S002', 'Hanako Tanaka', 'タナカ ハナコ', 'AM', '01'),
            'staff1': ('M001', 'Ken Sato', 'サトウ ケン', 'Staff', '02'),
        }
        self.db = MockUserDatabase(self.mock_users)
        self.processor = AttendanceProcessor(self.db.lookup_user)

    def test_simple_login_logout(self):
        """Test simple login and logout."""
        events = {
            'GRL-01': [
                [datetime(2024, 11, 27, 14, 30), 'on:user123'],
                [datetime(2024, 11, 27, 16, 30), 'off:user123'],
            ]
        }

        from_time = datetime(2024, 11, 27, 14, 0)
        to_time = datetime(2024, 11, 27, 17, 0)

        results = self.processor.process_events(events, from_time, to_time)

        self.assertEqual(len(results), 1)
        record = results[0]
        self.assertEqual(record[0], 'GRL-01')  # machine
        self.assertEqual(record[1], '14:30〜16:30')  # time range
        self.assertEqual(record[4], 'user123')  # user_id
        self.assertEqual(record[5], 'S001')  # student_no
        self.assertEqual(record[6], 'Taro Yamada')  # name

    def test_login_without_logout(self):
        """Test login without matching logout."""
        events = {
            'GRL-01': [
                [datetime(2024, 11, 27, 14, 30), 'on:user123'],
            ]
        }

        from_time = datetime(2024, 11, 27, 14, 0)
        to_time = datetime(2024, 11, 27, 17, 0)

        results = self.processor.process_events(events, from_time, to_time)

        self.assertEqual(len(results), 1)
        record = results[0]
        self.assertEqual(record[2], '---')  # logout time missing

    def test_orphaned_logout(self):
        """Test logout without matching login."""
        events = {
            'GRL-01': [
                [datetime(2024, 11, 27, 16, 30), 'off:user123'],
            ]
        }

        from_time = datetime(2024, 11, 27, 14, 0)
        to_time = datetime(2024, 11, 27, 17, 0)

        results = self.processor.process_events(events, from_time, to_time)

        self.assertEqual(len(results), 1)
        record = results[0]
        self.assertTrue(record[1].startswith('?〜'))  # login time unknown

    def test_double_login_rejection(self):
        """Test double login rejection."""
        events = {
            'GRL-01': [
                [datetime(2024, 11, 27, 14, 30), 'on:user123'],
                [datetime(2024, 11, 27, 14, 35), 'reject:user123:GRL-02'],
            ]
        }

        from_time = datetime(2024, 11, 27, 14, 0)
        to_time = datetime(2024, 11, 27, 17, 0)

        results = self.processor.process_events(events, from_time, to_time)

        # Login should be rejected (removed)
        self.assertEqual(len(results), 0)

    def test_startup_as_implicit_logout(self):
        """Test startup event as implicit logout."""
        events = {
            'GRL-01': [
                [datetime(2024, 11, 27, 14, 30), 'on:user123'],
                [datetime(2024, 11, 27, 16, 0), 'startup'],
            ]
        }

        from_time = datetime(2024, 11, 27, 14, 0)
        to_time = datetime(2024, 11, 27, 17, 0)

        results = self.processor.process_events(events, from_time, to_time)

        self.assertEqual(len(results), 1)
        record = results[0]
        self.assertEqual(record[2], '16:00')  # logout from startup

    def test_shutdown_as_implicit_logout(self):
        """Test shutdown event as implicit logout."""
        events = {
            'GRL-01': [
                [datetime(2024, 11, 27, 14, 30), 'on:user123'],
                [datetime(2024, 11, 27, 18, 0), 'shutdown'],
            ]
        }

        from_time = datetime(2024, 11, 27, 14, 0)
        to_time = datetime(2024, 11, 27, 19, 0)

        results = self.processor.process_events(events, from_time, to_time)

        self.assertEqual(len(results), 1)
        record = results[0]
        self.assertEqual(record[2], '18:00')

    def test_unknown_user(self):
        """Test handling of unknown user."""
        events = {
            'GRL-01': [
                [datetime(2024, 11, 27, 14, 30), 'on:unknown'],
            ]
        }

        from_time = datetime(2024, 11, 27, 14, 0)
        to_time = datetime(2024, 11, 27, 17, 0)

        results = self.processor.process_events(events, from_time, to_time)

        self.assertEqual(len(results), 1)
        record = results[0]
        self.assertEqual(record[5], '????')  # unknown student number
        self.assertEqual(record[6], 'unknown')  # user_id as name

    def test_multiple_machines(self):
        """Test events from multiple machines."""
        events = {
            'GRL-01': [
                [datetime(2024, 11, 27, 14, 30), 'on:user123'],
                [datetime(2024, 11, 27, 16, 30), 'off:user123'],
            ],
            'ML1-05': [
                [datetime(2024, 11, 27, 15, 0), 'on:user456'],
                [datetime(2024, 11, 27, 16, 0), 'off:user456'],
            ]
        }

        from_time = datetime(2024, 11, 27, 14, 0)
        to_time = datetime(2024, 11, 27, 17, 0)

        results = self.processor.process_events(events, from_time, to_time)

        self.assertEqual(len(results), 2)
        machines = [r[0] for r in results]
        self.assertIn('GRL-01', machines)
        self.assertIn('ML1-05', machines)


class TestFilterByRooms(unittest.TestCase):
    """Test room filtering."""

    def setUp(self):
        """Set up test fixtures."""
        mock_users = {'user123': ('S001', 'Test User', 'テスト', 'CS', '01')}
        self.db = MockUserDatabase(mock_users)
        self.processor = AttendanceProcessor(self.db.lookup_user)

    def test_filter_grl_room(self):
        """Test filtering by GRL room."""
        records = [
            ['GRL-01', '14:30', '16:30', 'on', 'user123', 'S001', 'Test', 'テスト', 'CS', '01', ''],
            ['ML1-01', '14:30', '16:30', 'on', 'user123', 'S001', 'Test', 'テスト', 'CS', '01', ''],
        ]

        room_filters = {'GRL': True, 'ML1': False, 'ML2': False, 'IML-A': False, 'IML-B': False}
        filtered = self.processor.filter_by_rooms(records, room_filters)

        self.assertEqual(len(filtered), 1)
        self.assertEqual(filtered[0][0], 'GRL-01')

    def test_filter_iml_subrooms(self):
        """Test filtering IML sub-rooms."""
        records = [
            ['IML-01', '14:30', '16:30', 'on', 'user123', 'S001', 'Test', 'テスト', 'CS', '01', ''],  # Room A
            ['IML-62', '14:30', '16:30', 'on', 'user123', 'S001', 'Test', 'テスト', 'CS', '01', ''],  # Room B
        ]

        # Test IML-A only
        room_filters = {'GRL': False, 'ML1': False, 'ML2': False, 'IML-A': True, 'IML-B': False}
        filtered = self.processor.filter_by_rooms(records, room_filters)
        self.assertEqual(len(filtered), 1)
        self.assertEqual(filtered[0][0], 'IML-01')

        # Test IML-B only
        room_filters = {'GRL': False, 'ML1': False, 'ML2': False, 'IML-A': False, 'IML-B': True}
        filtered = self.processor.filter_by_rooms(records, room_filters)
        self.assertEqual(len(filtered), 1)
        self.assertEqual(filtered[0][0], 'IML-62')

    def test_unique_users_filter(self):
        """Test unique users filtering."""
        records = [
            ['GRL-01', '14:30', '15:30', 'on', 'user123', 'S001', 'Test', 'テスト', 'CS', '01', ''],
            ['GRL-02', '15:45', '16:30', 'on', 'user123', 'S001', 'Test', 'テスト', 'CS', '01', ''],
        ]

        room_filters = {'GRL': True, 'ML1': False, 'ML2': False, 'IML-A': False, 'IML-B': False}

        # Without unique filter
        filtered = self.processor.filter_by_rooms(records, room_filters, unique_users=False)
        self.assertEqual(len(filtered), 2)

        # With unique filter
        filtered = self.processor.filter_by_rooms(records, room_filters, unique_users=True)
        self.assertEqual(len(filtered), 1)


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