from dataclasses import dataclass
from typing import Tuple
import requests
from requests import Response

from b4x_serializator import B4XSerializator


# version: 1.00

@dataclass
class DBResult:
    Tag: object
    Columns: dict
    Rows: list


@dataclass
class DBCommand:
    Name: str
    Parameters: Tuple


class DBRequestManager:
    VERSION = 2

    def __init__(self, connector_link: str):
        self.connector_link = connector_link
        self.serializator = B4XSerializator(types=[DBResult, DBCommand])

    def execute_query(self, command: DBCommand, limit: int = 0) -> DBResult:
        """
        Executes a query and returns the query result.
        """
        data: bytes = self.serializator.convert_object_to_bytes(
            {"command": command, "limit": limit, "version": self.VERSION})
        response = self._send_request("query2", data)
        return self.serializator.convert_bytes_to_object(response.content)

    def _send_request(self, method: str, data: bytes) -> Response:
        response = requests.post(self.connector_link + "?method=" + method, data)
        if response.status_code // 100 != 2:
            raise RuntimeError(response.reason)
        return response

    def execute_batch(self, list_of_commands: list[DBCommand]):
        """
        Executes one or more non-query commands.
        """
        data = self.serializator.convert_object_to_bytes({"commands": list_of_commands, "version": self.VERSION})
        self._send_request("batch2", data)

    def execute_command(self, command: DBCommand):
        """
        Executes a single non-query command.
        """
        self.execute_batch([command])

    def print_table(self, table: DBResult):
        """
        Utility to print DBResult.
        """
        print(f"Columns: {len(table.Columns)}, Rows: {len(table.Rows)}")
        sb = []
        for col in table.Columns.keys():
            sb.append(col)
            sb.append("\t")
        print("".join(sb))
        for row in table.Rows:
            sb = []
            for record in row:
                sb.append("blob" if isinstance(record, bytes) else str(record))
                sb.append("\t")
            print("".join(sb))
