"""aiotwitter client tests"""
from http import server, HTTPStatus
from random import randrange
from threading import Thread
from time import sleep
from unittest import mock, IsolatedAsyncioTestCase, TestCase

from ..aiotwitter import client, nonce


class MockAPI(server.BaseHTTPRequestHandler):
    """mock twitter backend"""

    def __init__(self, *args, **kwargs):
        """construct self"""
        super().__init__(*args, **kwargs)
        self.protocol_version = "HTTP/1.1"

    def do_DELETE(self):
        """mock delete resources"""
        if self.path == "/":
            self.send_response(HTTPStatus.OK)
            self.send_header("content-type", "text/json")
            self.end_headers()
            self.wfile('{"success": true}'.encode("latin-1"))
        elif self.path == "/mp":
            self.send_error(HTTPStatus.MOVED_PERMANENTLY)
        elif self.path == "/br":
            self.send_error(HTTPStatus.BAD_REQUEST)
        elif self.path == "/ise":
            self.send_error(HTTPStatus.INTERNAL_SERVER_ERROR)

    def do_GET(self):
        """mock get resources"""
        if self.path == "/2/tweets/sample/stream":
            for _ in range(10):
                self.wfile(
                    '{"data": {}}'.format(
                        nonce(10)
                    ).encode("latin-1")
                )
                sleep(randrange(0, 5))
        else:
            self.do_DELETE()

    def do_POST(self):
        """mock post resources"""
        self.do_DELETE()

    def do_PUT(self):
        """mock put resources"""
        self.do_DELETE()


class AsyncTestClient(IsolatedAsyncioTestCase):
    """client and client objects async unit tests"""

    def setUp(self):
        """spin up mock backend"""
        self.service = server.ThreadingHTTPServer(
            ("127.0.0.1", 80), MockAPI
        )
        t = Thread(target=self.service.serve_forever)
        t.start()

    def tearDown(self):
        """shut down mock backend"""
        self.service.shutdown()

    async def test_client_delete(self):
        """test client delete method"""
        pass

    async def test_client_get(self):
        """test client get method"""
        pass

    async def test_client_post(self):
        """test client post method"""
        pass

    async def test_client_put(self):
        """test client put method"""
        pass

    async def test_client_public_request(self):
        """test client public request method"""
        pass

    async def test_client_private_request(self):
        """test client private request method"""
        pass


class TestClient(TestCase):
    """client and client objects unit tests"""

    def test_request_exceptions(self):
        """test request exceptions"""
        #
        # show client.Request.__init__ requires authz param
        self.assertRaises(Exception, client.Request)
        #
        # show request method descriptor raises
        self.assertRaises(
            Exception,
            client.Request,
            "OPTIONS", "/", bearer_token="bt", authz="bearer"
        )
        #
        # show request resource descriptor raises
        self.assertRaises(
            Exception,
            client.Request,
            "GET", "", bearer_token="bt", authz="bearer"
        )
        #
        # show base request descriptor is immutable (1/2)
        with self.assertRaises(Exception):
            request = client.Request(
                "GET", "/", bearer_token="bt", authz="bearer"
            )
            del request.resource
        #
        # show base request descriptor is immutable (2/2)
        with self.assertRaises(Exception):
            request = client.Request(
                "GET", "/a", bearer_token="bt", authz="bearer"
            )
            request.resource = "/b"
        
    def test_concurrent_client_exceptions(self):
        """test non-async client exceptions"""
        #
        # show client.Request.__init__ warns withuot auth params
        with self.assertRaises(Warning):
            c = client.Client()