from pathlib import Path
from unittest import TestCase

from django.test import override_settings
from mock import patch, Mock, MagicMock
from django.conf import settings

from livesync.fswatcher import BaseEventHandler
from livesync.core.handler import LiveReloadRequestHandler


class BaseEventHandlerTestCase(TestCase):
    def setUp(self):
        self.handler = BaseEventHandler()
        self.mock_event = MagicMock(src_path='/path/file', dest_path='/path/newfile')

        self.getmd5_patcher = patch('livesync.fswatcher.handlers.get_md5', return_value='md5hash')
        self.mock_get_md5 = self.getmd5_patcher.start()

        self.handle_patcher = patch.object(self.handler, 'handle')
        self.mock_handle = self.handle_patcher.start()

    def tearDown(self):
        self.getmd5_patcher.stop()
        self.handle_patcher.stop()

    def test_on_deleted_remove_file_from_history(self):
        self.handler.history[self.mock_event.src_path] = "md5hash"
        # act
        self.handler.on_deleted(self.mock_event)
        # assert
        self.assertNotIn(self.mock_event.src_path, self.handler.history)

    def test_on_deleted_invokes_handle(self):
        self.handler.history[self.mock_event.src_path] = "md5hash"
        # act
        self.handler.on_deleted(self.mock_event)
        # assert
        self.mock_handle.assert_called_with(self.mock_event)

    def test_on_moved_updates_history(self):
        self.handler.history[self.mock_event.src_path] = "md5hash"
        # act
        self.handler.on_moved(self.mock_event)
        # assert
        self.assertNotIn(self.mock_event.src_path, self.handler.history)
        self.assertIn(self.mock_event.dest_path, self.handler.history)
        self.assertEqual(self.handler.history[self.mock_event.dest_path], 'md5hash')

    def test_on_moved_adds_to_history(self):
        # act
        self.handler.on_moved(self.mock_event)
        # assert
        self.assertIn(self.mock_event.dest_path, self.handler.history)
        self.assertEqual(self.handler.history[self.mock_event.dest_path], 'md5hash')

    def test_on_moved_invokes_handle(self):
        self.handler.history[self.mock_event.src_path] = "md5hash"
        # act
        self.handler.on_moved(self.mock_event)
        # assert
        self.mock_handle.assert_called_with(self.mock_event)

    def test_on_modified_adds_to_history(self):
        # act
        self.handler.on_modified(self.mock_event)
        # assert
        self.assertIn(self.mock_event.src_path, self.handler.history)
        self.assertEqual(self.handler.history[self.mock_event.src_path], 'md5hash')

    def test_on_modified_invoked_handle(self):
        # act
        self.handler.on_modified(self.mock_event)
        # assert
        self.mock_handle.assert_called_with(self.mock_event)

    def test_on_modified_ignores_unchanged_files(self):
        self.handler.history[self.mock_event.src_path] = "md5hash"
        #act
        self.handler.on_modified(self.mock_event)
        # assert
        self.mock_handle.assert_not_called()



class LiveReloadEventHandlerTestCase(TestCase):
    def setUp(self):
        self.handler = LiveReloadRequestHandler()

    @patch('livesync.core.handler.livesync_event.send')
    def test_handle_dispatches_event(self, mock_dispatch):
        # act
        self.handler.handle(Mock())
        # assert
        mock_dispatch.assert_called()

    @patch('livesync.core.middleware.settings.STATICFILES_DIRS',['foo', ])
    def test_handler_watches_staticfiles_dirs(self):
        self.assertIn('foo', self.handler.watched_paths)


    @patch('livesync.core.middleware.settings.TEMPLATES',[{'DIRS': ['foo', ]}])
    def test_handler_watches_template_dirs(self):
        self.assertIn('foo', self.handler.watched_paths)

    @patch('livesync.core.middleware.settings.STATICFILES_DIRS',['foo', ])
    @patch('livesync.core.middleware.settings.TEMPLATES',[{'DIRS': ['bar', ]}])
    def test_handler_combines_template_dirs_and_static_files(self):
        self.assertIn('foo', self.handler.watched_paths)
        self.assertIn('bar', self.handler.watched_paths)

    @override_settings(BASE_DIR=Path('/tmp/'))
    @patch('livesync.core.handler.get_app_template_dirs')
    def test_handle_pathlib_path(self, mock_app_template_dirs):
        mock_app_template_dirs.return_value = [Path('/tmp')]
        retval = self.handler.watched_paths
        self.assertTrue(hasattr(retval, '__iter__'))
