from __future__ import annotations

import subprocess
from dataclasses import dataclass


def sql_literal(value: object) -> str:
    if value is None:
        return "NULL"
    if isinstance(value, bool):
        return "TRUE" if value else "FALSE"
    text = str(value)
    return "'" + text.replace("'", "''") + "'"


@dataclass
class Database:
    url: str

    def execute(self, sql: str) -> None:
        subprocess.run(
            ["psql", self.url, "-X", "-v", "ON_ERROR_STOP=1", "-q"],
            input=sql,
            text=True,
            check=True,
        )

    def rows(self, sql: str) -> list[dict[str, str | None]]:
        result = subprocess.run(
            [
                "psql",
                self.url,
                "-X",
                "-v",
                "ON_ERROR_STOP=1",
                "-q",
                "-P",
                "footer=off",
                "-A",
                "-F",
                "\t",
                "-c",
                sql,
            ],
            text=True,
            check=True,
            capture_output=True,
        )
        lines = [line for line in result.stdout.splitlines() if line.strip()]
        if not lines:
            return []
        headers = lines[0].split("\t")
        out: list[dict[str, str | None]] = []
        for line in lines[1:]:
            values = line.split("\t")
            out.append(
                {
                    key: None if idx >= len(values) or values[idx] == "" else values[idx]
                    for idx, key in enumerate(headers)
                }
            )
        return out

    def one(self, sql: str) -> dict[str, str | None] | None:
        rows = self.rows(sql)
        return rows[0] if rows else None

