"""MySQL adapter for db-test-helpers."""

from __future__ import annotations

from datetime import date, datetime, timedelta
from decimal import Decimal
from typing import Any

from mysql.connector import MySQLConnection

from db_test_helpers.core._errors import UnsupportedError


def _check_parent_path(parent_path: str) -> None:
    if parent_path:
        raise UnsupportedError("MysqlAdapter does not support parent_path")


def _quote_identifier(name: str) -> str:
    if not name:
        raise ValueError("identifier must not be empty")
    return "`" + name.replace("`", "``") + "`"


class MysqlAdapter:
    """DatabaseAdapter for MySQL via mysql-connector-python.

    Args:
        conn: An open ``MySQLConnection``.
    """

    def __init__(self, conn: MySQLConnection) -> None:
        self._conn = conn

    def clear_group(self, group: str, parent_path: str) -> None:
        _check_parent_path(parent_path)
        cursor = self._conn.cursor()
        try:
            cursor.execute(f"DELETE FROM {_quote_identifier(group)}")
            self._conn.commit()
        except Exception:
            self._conn.rollback()
            raise
        finally:
            cursor.close()

    def write_record(self, group: str, parent_path: str, data: dict[str, Any]) -> dict[str, Any]:
        _check_parent_path(parent_path)
        if "__document_id__" in data:
            raise UnsupportedError("MysqlAdapter does not support __document_id__")
        data = dict(data)
        columns = list(data.keys())
        values = list(data.values())
        cols_str = ", ".join(_quote_identifier(c) for c in columns)
        placeholders = ", ".join(["%s"] * len(values))

        cursor = self._conn.cursor()
        try:
            cursor.execute(f"INSERT INTO {_quote_identifier(group)} ({cols_str}) VALUES ({placeholders})", values)
            self._conn.commit()
        except Exception:
            self._conn.rollback()
            raise
        finally:
            cursor.close()
        return data

    def read_records(self, group: str, parent_path: str) -> list[dict[str, Any]]:
        _check_parent_path(parent_path)
        cursor = self._conn.cursor(dictionary=True)
        try:
            cursor.execute(f"SELECT * FROM {_quote_identifier(group)}")
            rows = cursor.fetchall()
        finally:
            cursor.close()
        return [_from_mysql_types(row) for row in rows]


def _from_mysql_types(row: dict[str, Any]) -> dict[str, Any]:
    return {k: _convert_value(v) for k, v in row.items()}


def _convert_value(value: Any) -> Any:
    if value is None:
        return None
    if isinstance(value, Decimal):
        if value == int(value):
            return int(value)
        return float(value)
    if isinstance(value, datetime):
        return value.isoformat()
    if isinstance(value, date):
        return value.isoformat()
    if isinstance(value, timedelta):
        total_seconds = int(value.total_seconds())
        sign = "-" if total_seconds < 0 else ""
        total_seconds = abs(total_seconds)
        hours, remainder = divmod(total_seconds, 3600)
        minutes, seconds = divmod(remainder, 60)
        return f"{sign}{hours:02d}:{minutes:02d}:{seconds:02d}"
    if isinstance(value, bytes):
        return value.decode("utf-8")
    return value
