import json
import os
import shutil
from os.path import join

from bzt import TaurusConfigError
from bzt.modules.proxy2jmx import Proxy2JMX, BZAProxy
from bzt.modules._selenium import SeleniumExecutor
from bzt.utils import is_windows, is_linux, get_full_path, RESOURCES_DIR
from tests.unit import BZTestCase, EngineEmul


class BZAProxyEmul(BZAProxy):
    def __init__(self, service):
        super(BZAProxyEmul, self).__init__()
        self.service = service

    def _request(self, url, data=None, headers=None, method=None, raw_result=False):
        self.log.debug("Emulating: %s", url)
        response = self.service.responses.pop(0)
        resp = response.text
        self.log.debug("Result: %s", resp)
        if raw_result:
            return resp
        else:
            return json.loads(resp) if len(resp) else {}


class Proxy2JMXEmul(Proxy2JMX):
    responses = []

    def __init__(self):
        super(Proxy2JMXEmul, self).__init__()
        self.proxy = BZAProxyEmul(self)


class ResponseEmul(object):
    def __init__(self, status_code, text):
        self.status_code = status_code
        self.text = text


class TestProxy2JMX(BZTestCase):
    def setUp(self):
        super(TestProxy2JMX, self).setUp()
        self.obj = Proxy2JMXEmul()
        self.obj.engine = EngineEmul()
        src = join(RESOURCES_DIR, 'chrome-loader.c')
        dst_loader = join(RESOURCES_DIR, 'chrome-loader.exe')
        shutil.copy2(src, dst_loader)

    def tearDown(self):
        dst_loader = join(RESOURCES_DIR, 'chrome-loader.exe')
        os.remove(dst_loader)
        super(TestProxy2JMX, self).tearDown()

    def test_no_token(self):
        self.obj.settings = self.obj.engine.config.get('recorder')
        self.assertRaises(TaurusConfigError, self.obj.prepare)

    def test_full(self):
        self.obj.api_delay = 1
        self.obj.responses = [
            ResponseEmul(200, '{"result" : {}}'),
            ResponseEmul(200, '{"result" : {"port": "port1", "host": "host1"}}'),
            ResponseEmul(200, ''),
            ResponseEmul(200, ''),  # startup: startRecording
            ResponseEmul(200, ''),  # shutdown: stopRecording
            ResponseEmul(200, '{"result" : "http://jmx_url"}'),
            ResponseEmul(200, 'regular jmx contents'),
            ResponseEmul(200, '{"result" : "http://smartjmx_url"}'),
            ResponseEmul(200, 'smartjmx content')]

        self.obj.engine.config.merge({
            'modules': {
                'recorder': {
                    'token': '123'}}})
        self.obj.settings = self.obj.engine.config.get('modules').get('recorder')

        executor = SeleniumExecutor()
        self.obj.engine.provisioning.executors = [executor]

        self.obj.prepare()
        self.assertEqual(self.obj.proxy_addr, 'http://host1:port1')

        self.obj.startup()
        self.obj.shutdown()
        self.obj.post_process()

        with open(self.obj.engine.artifacts_dir + '/generated.smart.jmx') as fd:
            lines = fd.readlines()
            self.assertEqual(len(lines), 1)
            self.assertEqual(lines[0].strip(), 'smartjmx content')

        with open(self.obj.engine.artifacts_dir + '/generated.simple.jmx') as fd:
            lines = fd.readlines()
            self.assertEqual(len(lines), 1)
            self.assertEqual(lines[0].strip(), 'regular jmx contents')

    def test_existing_proxy(self):
        self.obj.api_delay = 1
        self.obj.responses = [
            ResponseEmul(200,
                         '{"result" : {"port": "port1", "host": "host1", "status": "active"}}'),
            ResponseEmul(200, ''),  # stopRecording
            ResponseEmul(200, '')]  # clearRecording

        self.obj.engine.config.merge({
            'modules': {
                'recorder': {
                    'token': '123'}}})
        self.obj.settings = self.obj.engine.config.get('modules').get('recorder')

        self.obj.prepare()
        self.assertEqual(self.obj.proxy_addr, 'http://host1:port1')

    def test_filename(self):
        self.obj.api_delay = 1
        self.obj.responses = [
            ResponseEmul(200,
                         '{"result" : {"port": "port1", "host": "host1", "status": "active"}}'),
            ResponseEmul(200, '1'),  # stopRecording
            ResponseEmul(200, '2'),  # clearRecording
            ResponseEmul(200, '{"result" : "http://jmx_url"}'),
            ResponseEmul(200, 'regular jmx contents'),
            ResponseEmul(200, '{"result" : "http://smartjmx_url"}'),
            ResponseEmul(200, 'smartjmx content')
        ]

        self.obj.engine.config.merge({'modules': {'recorder': {'token': '123'}}})
        self.obj.settings = self.obj.engine.config.get('modules').get('recorder')
        self.obj.parameters['simple-output'] = self.obj.engine.artifacts_dir + '/simple.jmx'
        self.obj.parameters['smart-output'] = self.obj.engine.artifacts_dir + '/smart.jmx'

        self.obj.prepare()
        self.obj.post_process()
        self.assertTrue(os.path.exists(self.obj.engine.artifacts_dir + "/smart.jmx"))
        self.assertTrue(os.path.exists(self.obj.engine.artifacts_dir + "/simple.jmx"))

    def _check_linux(self):
        required_env = {
            'DESKTOP_SESSION': None, 'HTTP_PROXY': 'http://host1:port1', 'https_proxy': 'http://host1:port1',
            'GNOME_DESKTOP_SESSION_ID': None, 'http_proxy': 'http://host1:port1', 'XDG_CURRENT_DESKTOP': None,
            'HTTPS_PROXY': 'http://host1:port1', 'CHROMIUM_USER_FLAGS': '--proxy-server=http://host1:port1',
            'KDE_FULL_SESSION': None}

        self.obj.startup()

        real_env = self.obj.engine.provisioning.executors[0].env.get()
        for key in required_env:
            if required_env[key] is None:
                self.assertNotIn(key, real_env)
            else:
                self.assertIn(key, real_env)
                self.assertEqual(required_env[key], real_env[key], key)

    def _check_windows(self):
        art_dir = self.obj.engine.artifacts_dir
        os.environ['LOCALAPPDATA'] = art_dir
        os.mkdir(join(art_dir, 'Chromium'))
        os.mkdir(join(art_dir, 'Chromium', 'Application'))
        os.mkdir(join(art_dir, 'chromedriver'))
        src = join(RESOURCES_DIR, 'chrome-loader.c')

        dst_chrome = join(art_dir, 'Chromium', 'Application', 'chrome.exe')
        dst_chromedriver = join(art_dir, 'chromedriver', 'chromedriver.exe')

        shutil.copy2(src, dst_chrome)