"""
Unit tests for SettingsManager.

Tests settings management in isolation using mocks.
"""

import unittest
from unittest.mock import Mock, MagicMock

from dreader.managers.settings import SettingsManager


class TestSettingsManager(unittest.TestCase):
    """Test SettingsManager in isolation"""

    def setUp(self):
        """Set up test environment"""
        self.manager = SettingsManager()

    def test_initialization(self):
        """Test manager initializes correctly"""
        manager = SettingsManager()

        self.assertEqual(manager.font_scale, 1.0)
        self.assertEqual(manager.font_scale_step, 0.1)
        self.assertIsNone(manager.manager)

    def test_get_font_size(self):
        """Test getting current font size"""
        self.assertEqual(self.manager.get_font_size(), 1.0)

        self.manager.font_scale = 1.5
        self.assertEqual(self.manager.get_font_size(), 1.5)

    def test_set_font_size_without_manager(self):
        """Test setting font size without layout manager returns None"""
        result = self.manager.set_font_size(1.5)
        self.assertIsNone(result)

    def test_set_font_size_with_manager(self):
        """Test setting font size with layout manager"""
        # Create mock manager
        mock_layout_manager = Mock()
        mock_page = Mock()
        mock_page.render.return_value = "rendered_page"
        mock_layout_manager.set_font_scale.return_value = mock_page
        mock_layout_manager.font_scale = 1.0

        self.manager.set_manager(mock_layout_manager)

        # Set font size
        result = self.manager.set_font_size(1.5)

        self.assertIsNotNone(result)
        self.assertEqual(result, "rendered_page")
        self.assertEqual(self.manager.font_scale, 1.5)
        mock_layout_manager.set_font_scale.assert_called_once_with(1.5)

    def test_font_size_clamping(self):
        """Test font size is clamped between 0.5x and 3.0x"""
        mock_layout_manager = Mock()
        mock_page = Mock()
        mock_page.render.return_value = "rendered_page"
        mock_layout_manager.set_font_scale.return_value = mock_page
        mock_layout_manager.font_scale = 1.0

        self.manager.set_manager(mock_layout_manager)

        # Test upper bound
        self.manager.set_font_size(5.0)
        self.assertEqual(self.manager.font_scale, 3.0)

        # Test lower bound
        self.manager.set_font_size(0.1)
        self.assertEqual(self.manager.font_scale, 0.5)

    def test_increase_font_size(self):
        """Test increasing font size by one step"""
        mock_layout_manager = Mock()
        mock_page = Mock()
        mock_page.render.return_value = "rendered_page"
        mock_layout_manager.set_font_scale.return_value = mock_page
        mock_layout_manager.font_scale = 1.0

        self.manager.set_manager(mock_layout_manager)

        initial_size = self.manager.font_scale
        self.manager.increase_font_size()

        self.assertEqual(self.manager.font_scale, initial_size + 0.1)

    def test_decrease_font_size(self):
        """Test decreasing font size by one step"""
        mock_layout_manager = Mock()
        mock_page = Mock()
        mock_page.render.return_value = "rendered_page"
        mock_layout_manager.set_font_scale.return_value = mock_page
        mock_layout_manager.font_scale = 1.5

        self.manager.set_manager(mock_layout_manager)
        self.manager.font_scale = 1.5

        self.manager.decrease_font_size()

        self.assertAlmostEqual(self.manager.font_scale, 1.4, places=5)

    def test_set_line_spacing(self):
        """Test setting line spacing"""
        mock_layout_manager = Mock()
        mock_page = Mock()
        mock_page.render.return_value = "rendered_page"
        mock_layout_manager.get_current_page.return_value = mock_page
        mock_layout_manager.page_style = Mock()
        mock_layout_manager.page_style.line_spacing = 5

        self.manager.set_manager(mock_layout_manager)

        result = self.manager.set_line_spacing(10)

        self.assertIsNotNone(result)
        mock_layout_manager.increase_line_spacing.assert_called_once_with(5)

    def test_set_inter_block_spacing(self):
        """Test setting inter-block spacing"""
        mock_layout_manager = Mock()
        mock_page = Mock()
        mock_page.render.return_value = "rendered_page"
        mock_layout_manager.get_current_page.return_value = mock_page
        mock_layout_manager.page_style = Mock()
        mock_layout_manager.page_style.inter_block_spacing = 15

        self.manager.set_manager(mock_layout_manager)

        result = self.manager.set_inter_block_spacing(25)

        self.assertIsNotNone(result)
        mock_layout_manager.increase_inter_block_spacing.assert_called_once_with(10)

    def test_set_word_spacing(self):
        """Test setting word spacing"""
        mock_layout_manager = Mock()
        mock_page = Mock()
        mock_page.render.return_value = "rendered_page"
        mock_layout_manager.get_current_page.return_value = mock_page
        mock_layout_manager.page_style = Mock()
        mock_layout_manager.page_style.word_spacing = 0

        self.manager.set_manager(mock_layout_manager)

        result = self.manager.set_word_spacing(3)

        self.assertIsNotNone(result)
        mock_layout_manager.increase_word_spacing.assert_called_once_with(3)

    def test_get_current_settings_without_manager(self):
        """Test getting settings without layout manager"""
        settings = self.manager.get_current_settings()

        self.assertIsInstance(settings, dict)
        self.assertEqual(settings['font_scale'], 1.0)
        self.assertEqual(settings['line_spacing'], 5)
        self.assertEqual(settings['inter_block_spacing'], 15)
        self.assertEqual(settings['word_spacing'], 0)

    def test_get_current_settings_with_manager(self):
        """Test getting settings with layout manager"""
        mock_layout_manager = Mock()
        mock_layout_manager.page_style = Mock()
        mock_layout_manager.page_style.line_spacing = 10
        mock_layout_manager.page_style.inter_block_spacing = 20
        mock_layout_manager.page_style.word_spacing = 3
        mock_layout_manager.font_scale = 1.5

        self.manager.set_manager(mock_layout_manager)
        self.manager.font_scale = 1.5

        settings = self.manager.get_current_settings()

        self.assertEqual(settings['font_scale'], 1.5)
        self.assertEqual(settings['line_spacing'], 10)
        self.assertEqual(settings['inter_block_spacing'], 20)
        self.assertEqual(settings['word_spacing'], 3)

    def test_apply_settings(self):
        """Test applying settings from dictionary"""
        mock_layout_manager = Mock()
        mock_page = Mock()
        mock_page.render.return_value = "rendered_page"
        mock_layout_manager.set_font_scale.return_value = mock_page
        mock_layout_manager.get_current_page.return_value = mock_page
        mock_layout_manager.page_style = Mock()
        mock_layout_manager.page_style.line_spacing = 5
        mock_layout_manager.page_style.inter_block_spacing = 15
        mock_layout_manager.page_style.word_spacing = 0
        mock_layout_manager.font_scale = 1.0

        self.manager.set_manager(mock_layout_manager)

        settings = {
            'font_scale': 1.5,
            'line_spacing': 10,
            'inter_block_spacing': 20,
            'word_spacing': 3
        }

        success = self.manager.apply_settings(settings)

        self.assertTrue(success)
        self.assertEqual(self.manager.font_scale, 1.5)

    def test_apply_settings_without_manager(self):
        """Test applying settings without layout manager returns False"""
        settings = {'font_scale': 1.5}
        success = self.manager.apply_settings(settings)

        self.assertFalse(success)


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