#!/usr/bin/env python3
# -*- coding: utf-8 -*-

from typing import Any, Self
from Utils.Check import Check
from Utils.Patterns import RE
from Utils.Utils import Utils
from re import Match as REMatch
from socket import socket as Socket

class RequestModel:

    def __init__(self:Self, data:str, inputs:dict[str, Any|None]) -> None:

        header:list[str]
        line:str

        self.address:str = inputs.get("address")
        self.port:int = inputs.get("port")
        self.client:Socket = inputs.get("client")
        self.public_path:str = inputs.get("public_path")
        self.index_files:list[str] = inputs.get("index_files")
        self.method:str
        self.request:str
        self.protocol:str
        self.protocol_version:str
        self.variables_get:dict[str, str] = {}
        self.variables_post:dict[str, str] = {}
        self.variables_request:dict[str, str] = {}
        self.headers:dict[str, str] = {}
        self.body:str|None

        header, self.body = (lambda header, body:(
            RE.NEW_LINE.split(str(header).strip()), body
        ))(*RE.HTTP_BLOCKS.match(data).groups())

        (
            self.method, 
            self.request, 
            self.variables_get, 
            self.protocol, 
            self.protocol_version
        ) = (lambda method, request, variables, protocol, protocol_version:(
            str(method).lower(), 
            request, 
            self.parse_variables(variables), 
            protocol, 
            protocol_version
        ))(*RE.HTTP_REQUEST.match(header[0]).groups())

        for line in header[1:]:

            key:str
            value:str

            key, value = RE.HEADER_LINE.match(line).groups()

            self.headers[key.strip().lower()] = value.strip()

        self.variables_post = self.parse_variables(self.body or "")

    @staticmethod
    def parse_variables_set(data:str) -> dict[str, str]:

        json:dict[str, str]|list[Any|None]|tuple[Any|None]|None = Utils.json_decode(data)

        if Check.is_dictionary(json):
            return json
        return {key : value for key, value in RE.URI_VARIABLES.findall(data) or []}

    @classmethod
    def parse_variables(cls:type[Self], data:str|None) -> dict[str, str]:
        return cls.parse_variables_set(
            Utils.base64_decode(data) or data
        ) if data else {}
    
    def set_request_variables(self:Self, matches:REMatch, keys:tuple[str]) -> None:
        self.variables_request = {keys[i] : value for i, value in enumerate(matches.groups()[1:])}