from __future__ import print_function
from __future__ import unicode_literals
from future import standard_library
standard_library.install_aliases()
import http.client
import threading
import time
import unittest
import urllib.request, urllib.error, urllib.parse

import mock
import responses

from cumulusci.oauth.salesforce import CaptureSalesforceOAuth
from cumulusci.oauth.exceptions import SalesforceOAuthError


@mock.patch('webbrowser.open', mock.MagicMock(return_value=None))
class TestCaptureSalesforceOAuth(unittest.TestCase):

    def _create_oauth(self):
        return CaptureSalesforceOAuth(
            self.client_id,
            self.client_secret,
            self.callback_url,
            self.auth_site,
            self.scope,
        )

    def setUp(self):
        self.client_id = 'foo_id'
        self.client_secret = 'foo_secret'
        self.callback_url = 'http://localhost:8080'
        self.scope = 'refresh_token web full'
        self.auth_site = 'https://login.salesforce.com'

    @responses.activate
    def test_oauth_flow(self):

        # mock response to URL validation
        responses.add(
            responses.GET,
            'https://login.salesforce.com/services/oauth2/authorize',
            status=http.client.OK,
        )

        # mock response for SalesforceOAuth2.get_token()
        expected_response = {
            u'access_token': u'abc123',
            u'id_token': u'abc123',
            u'token_type': u'Bearer',
            u'signature': u'abc123',
            u'issued_at': u'12345',
            u'scope': u'{}'.format(self.scope),
            u'instance_url': u'https://na15.salesforce.com',
            u'id': u'https://login.salesforce.com/id/abc/xyz',
            u'refresh_token': u'abc123',
        }
        responses.add(
            responses.POST,
            'https://login.salesforce.com/services/oauth2/token',
            status=http.client.OK,
            json=expected_response,
        )

        # create CaptureSalesforceOAuth instance
        o = self._create_oauth()

        # call OAuth object on another thread - this spawns local httpd
        t = threading.Thread(target=o.__call__)
        t.start()
        while True:
            if o.httpd:
                break
            print('waiting for o.httpd')
            time.sleep(0.01)

        # simulate callback from browser
        response = urllib.request.urlopen(self.callback_url + '?code=123')

        # wait for thread to complete
        t.join()

        # verify
        self.assertEqual(o.response.json(), expected_response)
        self.assertEqual(response.read(), b'OK')

    @responses.activate
    def test_bad_request(self):

        # mock response to URL validation
        responses.add(
            responses.GET,
            'https://login.salesforce.com/services/oauth2/authorize',
            status=http.client.BAD_REQUEST,
        )

        # create CaptureSalesforceOAuth instance
        o = self._create_oauth()

        # call OAuth object with bad info
        with self.assertRaises(SalesforceOAuthError):
            o()


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