import contextlib
import os
import tempfile
import unittest
from importlib import reload
from io import StringIO
import responses
from a28 import account, config, utils
from a28.config import ConfigFile


class TestAccountMethods(unittest.TestCase):
    def setUp(self) -> None:
        self.test_dir = tempfile.TemporaryDirectory()
        utils.CONFIG_PATH = self.test_dir.name
        utils.CONFIG = os.path.join(utils.CONFIG_PATH, 'config.json')

        reload(config)

        self.responses = responses.RequestsMock()
        self.responses.start()

        self.temp_stdout = StringIO()

        self.addCleanup(self.responses.stop)
        self.addCleanup(self.responses.reset)

    def tearDown(self) -> None:
        self.test_dir.cleanup()

    def test_authenticate_with_valid_response(self):
        self.responses.add(
            responses.GET,
            'https://assets.a28.io/plugin/endpoints.json',
            json={
                "international": {
                    "api": {
                        "endpoint": "https://api.example.com/v1"
                    }
                }
            },
            status=200
        )

        self.responses.add(
            responses.POST,
            'https://api.example.com/v1/account/signin',
            json={
                "statusCode": 200,
                "status": "SUCCESS",
                "token": "supersecrettoken11"
            },
            status=200
        )
        self.assertEqual({}, ConfigFile.load())

        with contextlib.redirect_stdout(self.temp_stdout):
            account.authenticate(region="international", email="joe@example.com", password="123")

        self.assertEqual("authentication successful", self.temp_stdout.getvalue().strip())
        self.assertEqual(
            {
                'international': {
                    'email': 'joe@example.com',
                    'token': 'supersecrettoken11'
                }
            },
            ConfigFile.load()
        )

    def test_authenticate_with_unauthorized_response(self):
        self.responses.add(
            responses.GET,
            'https://assets.a28.io/plugin/endpoints.json',
            json={
                "international": {
                    "api": {
                        "endpoint": "https://api.example.com/v1"
                    }
                }
            },
            status=200
        )

        self.responses.add(
            responses.POST,
            'https://api.example.com/v1/account/signin',
            json={
                "statusCode": 402,
                "status": "ERROR",
                "message": "you can't"
            },
            status=402
        )
        self.assertEqual({}, ConfigFile.load())

        with contextlib.redirect_stdout(self.temp_stdout):
            account.authenticate(region="international", email="joe@example.com", password="123")

        self.assertEqual("error authenticating: you can't", self.temp_stdout.getvalue().strip())
        self.assertEqual({}, ConfigFile.load())

    def test_authenticate_with_failed_response(self):
        self.responses.add(
            responses.GET,
            'https://assets.a28.io/plugin/endpoints.json',
            json={
                "international": {
                    "api": {
                        "endpoint": "https://api.example.com/v1"
                    }
                }
            },
            status=200
        )

        self.responses.add(
            responses.POST,
            'https://api.example.com/v1/account/signin',
            json={},
            status=500
        )
        self.assertEqual({}, ConfigFile.load())

        with contextlib.redirect_stdout(self.temp_stdout):
            account.authenticate(region="international", email="joe@example.com", password="123")

        self.assertEqual("error authenticating: 500", self.temp_stdout.getvalue().strip())
        self.assertEqual({}, ConfigFile.load())
