import os
import json_stream
from base64 import b64decode
from typing import Iterator


# a heuristic to determine if a fileis a har archive
def har_archive_heuristic(file_path: str) -> int:
    val = 0
    # if has the har extension
    if file_path.endswith(".har"):
        val += 15
    # read the first 2048 bytes
    with open(file_path, "rb") as f:
        data = f.read(2048)
        # if file contains only ascii characters
        if data.decode("utf-8", "ignore").isprintable() is True:
            val += 25
        # if first character is a '{'
        if data[0] == "{":
            val += 23
        # if it contains the word '"WebInspector"'
        if b'"WebInspector"' in data:
            val += 15
        # if it contains the word '"entries"'
        if b'"entries"' in data:
            val += 15
        # if it contains the word '"version"'
        if b'"version"' in data:
            val += 15
    return val


class HarFlowWrapper:
    def __init__(self, flow: dict):
        self.flow = flow

    def get_url(self):
        return self.flow["request"]["url"]

    def get_method(self):
        return self.flow["request"]["method"]

    def get_request_headers(self):
        headers = {}
        for kv in self.flow["request"]["headers"]:
            k = kv["name"]
            v = kv["value"]
            # create list on key if it does not exist
            headers[k] = headers.get(k, [])
            headers[k].append(v)

    def get_request_body(self):
        if (
            "request" in self.flow
            and "postData" in self.flow["request"]
            and "text" in self.flow["request"]["postData"]
        ):
            return self.flow["request"]["postData"]["text"]
        return None

    def get_response_status_code(self):
        return self.flow["response"]["status"]

    def get_response_reason(self):
        return self.flow["response"]["statusText"]

    def get_response_headers(self):
        headers = {}
        for kv in self.flow["response"]["headers"]:
            k = kv["name"]
            v = kv["value"]
            # create list on key if it does not exist
            headers[k] = headers.get(k, [])
            headers[k].append(v)
        return headers

    def get_response_body(self):
        if (
            "response" in self.flow
            and "content" in self.flow["response"]
            and "text" in self.flow["response"]["content"]
        ):
            if (
                "encoding" in self.flow["response"]["content"]
                and self.flow["response"]["content"]["encoding"] == "base64"
            ):
                return b64decode(self.flow["response"]["content"]["text"]).decode()
            return self.flow["response"]["content"]["text"]
        return None


class HarCaptureReader:
    def __init__(self, file_path: str, progress_callback=None):
        self.file_path = file_path
        self.progress_callback = progress_callback

    def captured_requests(self) -> Iterator[HarFlowWrapper]:
        har_file_size = os.path.getsize(self.file_path)
        with open(self.file_path, "r", encoding="utf-8") as f:
            data = json_stream.load(f)
            for entry in data["log"]["entries"].persistent():
                if self.progress_callback:
                    self.progress_callback(f.tell() / har_file_size)
                yield HarFlowWrapper(entry)

    def name(self):
        return "har"
