import json
import time
from datetime import timedelta

import os
from autobahn.wamp import ApplicationError, TransportLost
from mock import mock, call
from pyfakefs.fake_filesystem_unittest import Patcher

from mdstudio.api.exception import CallException
from mdstudio.deferred.chainable import test_chainable
from mdstudio.logging.impl.session_observer import SessionLogObserver
from mdstudio.logging.log_type import LogType
from mdstudio.unittest.db import DBTestCase
from mdstudio.utc import from_utc_string, now, to_utc_string, timestamp

# Python 2 compatibility.
try:
    TimeoutError
except NameError:
    import socket
    TimeoutError = socket.timeout

class SessionObserverTests(DBTestCase):

    def setUp(self):
        SessionLogObserver._instance = None
        self.session = mock.MagicMock()
        self.session.__str__ = mock.MagicMock(return_value='"MagicMock"')
        self.session.component_root_path = mock.MagicMock(return_value='/')

        self.observer = SessionLogObserver(self.session)
        self.observer.flusher = mock.MagicMock()

    def tearDown(self):
        SessionLogObserver._instance = None

    def test_construction(self):
        self.assertEqual(self.observer.session, None)
        self.assertEqual(self.observer.sessions, [])
        self.assertEqual(self.observer.log_type, LogType.User)

        self.assertLessEqual(now() - from_utc_string(self.observer.logs[0]['time']), timedelta(seconds=1))
        del self.observer.logs[0]['time']
        self.assertEqual(self.observer.logs, [{
            'level': 'info',
            'source': 'mdstudio.logging.impl.session_observer.SessionLogObserver',
            'message': 'Collecting logs on session "MagicMock"'
        }])
        self.assertEqual(self.observer.flushing, False)
        self.assertEqual(os.path.abspath(self.observer.recovery_file(self.session)), os.path.abspath('/logs/recovery.json'))

    def test_call(self):
        t = now()
        self.observer({
            'log_format': 'hello {str}',
            'log_namespace': 'test namespace',
            'log_level': LogType.Group,
            'log_time': timestamp(t),
            'str': 'test'
        })

        self.assertLessEqual(t - from_utc_string(self.observer.logs[1]['time']), timedelta(seconds=1))
        del self.observer.logs[1]['time']
        self.assertEqual(self.observer.logs[1], {
            'level': 'Group',
            'source': 'test namespace',
            'message': 'hello test'
        })

    def test_call2(self):
        t = now()
        self.observer({
            'message': 'hello test',
            'log_namespace': 'test namespace',
            'log_level': LogType.Group,
            'log_time': timestamp(t),
        })

        self.assertLessEqual(t - from_utc_string(self.observer.logs[1]['time']), timedelta(seconds=1))
        del self.observer.logs[1]['time']
        self.assertEqual(self.observer.logs[1], {
            'level': 'Group',
            'source': 'test namespace',
            'message': 'hello test'
        })

    def test_call3(self):
        self.observer({