from http import HTTPStatus
from io import BytesIO, StringIO
import re
from typing import List

from asserts import assert_false, assert_regex, assert_equal, assert_true

from rouver.types import StartResponseReturnType, HeaderType, EnvironmentType

_status_re = re.compile(r"^(\d\d\d) (.*)$")


class StartResponse:

    def __init__(self) -> None:
        self.was_called = False
        self.status = ""
        self.headers = []  # type: List[HeaderType]

    def __call__(self, status: str, headers: List[HeaderType]) \
            -> StartResponseReturnType:
        assert_false(self.was_called, "start_response() called twice")
        assert_regex(status, _status_re)
        self.was_called = True
        self.status = status
        self.headers = headers
        return lambda s: None

    @property
    def status_code(self) -> int:
        self.assert_was_called()
        assert len(self.status) >= 3
        return int(self.status[:3])

    def assert_was_called(self) -> None:
        assert_true(self.was_called, "start_response() was not called")

    def assert_status(self, status: HTTPStatus) -> None:
        assert_equal(status.value, self.status_code)

    def assert_header_equals(self, name: str, value: str) -> None:
        header_value = self._find_header(name)
        assert_equal(value, header_value, "'{}': '{}' != '{}".format(
            name, value, header_value))

    def _find_header(self, name: str) -> str:
        self.assert_was_called()
        for (header_name, header_value) in self.headers:
            if header_name.lower() == name.lower():
                return header_value
        raise AssertionError("missing header '{}'".format(name))


def default_environment() -> EnvironmentType:
    return {
        "REQUEST_METHOD": "GET",
        "SERVER_NAME": "www.example.com",
        "SERVER_PORT": "80",
        "SERVER_PROTOCOL": "HTTP/1.1",
        "wsgi.version": (1, 0),
        "wsgi.url_scheme": "http",
        "wsgi.input": BytesIO(b""),
        "wsgi.errors": StringIO(),
        "wsgi.multithread": False,
        "wsgi.multiprocess": False,
        "wsgi.run_once": False,
    }
