# coding:utf-8

import typing as t

from makit.lib.encoding import decode, encode


class Headers(t.Mapping[str, str]):
    """
    Http Headers
    """

    def __init__(self, raw=None, scope=None, charset='"latin-1"', **kwargs):
        self._raw_data = raw or []
        self.charset = charset
        if scope:
            for k, v in scope.get('headers'):
                self[k] = v
        for k, v in kwargs.items():
            self[k] = v

    @property
    def raw_data(self):
        return self._raw_data

    def keys(self):
        return [decode(k, encoding=self.charset) for k, v in self._raw_data]

    def values(self):
        return [decode(v, encoding=self.charset) for k, v in self._raw_data]

    def items(self):
        return [
            (decode(key, self.charset), decode(value, self.charset))
            for key, value in self._raw_data
        ]

    def get(self, key: t.Union[str, bytes], default=None):
        try:
            return self[key]
        except KeyError:
            return default

    def setdefault(self, key: str, value):
        value = decode(value, encoding=self.charset)
        if key not in self.keys():
            self[key] = value
        return value

    def add_vary_header(self, vary: str) -> None:
        existing = self.get("vary")
        if existing is not None:
            vary = ", ".join([existing, vary])
        self["vary"] = vary

    def update(self, **kwargs):
        for k, v in kwargs.items():
            self[k] = v

    def remove(self, key):
        for item in self._raw_data:
            k = decode(item[0], encoding=self.charset)
            if k == key:
                self._raw_data.remove(item)
                break

    def __contains__(self, item: t.Union[str, bytes]):
        item = encode(item.lower(), encoding=self.charset)
        for k, v in self._raw_data:
            if k == item:
                return True
        return False

    def __setitem__(self, key: t.Union[str, bytes], value):
        key = key.lower()
        key = encode(key, encoding=self.charset)
        for item in self._raw_data:
            if item[0] == key:
                self._raw_data.remove(item)
                break
        self._raw_data.append(
            (key, encode(value, encoding=self.charset))
        )

    def __getitem__(self, k: t.Union[str, bytes]) -> str:
        item = encode(k.lower(), encoding=self.charset)
        if self._raw_data:
            for k, v in self._raw_data:
                if k == item:
                    return decode(v, encoding=self.charset)
        raise KeyError(k)

    def __len__(self) -> int:
        return len(self._raw_data)

    def __iter__(self):
        for k, v in self._raw_data:
            key = decode(k, encoding=self.charset)
            value = decode(v, encoding=self.charset)
            yield key, value
