import json
import aiosqlite
import os
from typing import Any
from .plugin_storage import PluginStorage
from astrbot.core.utils.astrbot_path import get_astrbot_data_path

DBPATH = os.path.join(get_astrbot_data_path(), "plugin_data", "sqlite", "plugin_data.db")


class SQLitePluginStorage(PluginStorage):
    """插件数据的 SQLite 存储实现类。

    该类提供异步方式将插件数据存储到 SQLite 数据库中，支持数据的增删改查操作。
    所有数据以 (plugin, key) 作为复合主键进行索引。
    """

    _instance = None  # Standalone instance of the class
    _db_conn = None
    db_path = None

    def __new__(cls):
        """
        创建或获取 SQLitePluginStorage 的单例实例。
        如果实例已存在，则返回现有实例；否则创建一个新实例。
        数据在 `data/plugin_data/sqlite/plugin_data.db` 下。
        """
        os.makedirs(os.path.dirname(DBPATH), exist_ok=True)
        if cls._instance is None:
            cls._instance = super(SQLitePluginStorage, cls).__new__(cls)
            cls._instance.db_path = DBPATH
        return cls._instance

    async def _init_db(self):
        """初始化数据库连接（只执行一次）"""
        if SQLitePluginStorage._db_conn is None:
            SQLitePluginStorage._db_conn = await aiosqlite.connect(self.db_path)
            await self._setup_db()

    async def _setup_db(self):
        """
        异步初始化数据库。

        创建插件数据表，如果表不存在则创建，表结构包含 plugin、key 和 value 字段，
        其中 plugin 和 key 组合作为主键。
        """
        await self._db_conn.execute("""
            CREATE TABLE IF NOT EXISTS plugin_data (
                plugin TEXT,
                key TEXT,
                value TEXT,
                PRIMARY KEY (plugin, key)
            )
        """)
        await self._db_conn.commit()

    async def set(self, plugin: str, key: str, value: Any):
        """
        异步存储数据。

        将指定插件的键值对存入数据库，如果键已存在则更新值。
        值会被序列化为 JSON 字符串后存储。

        Args:
            plugin: 插件标识符
            key: 数据键名
            value: 要存储的数据值（任意类型，将被 JSON 序列化）
        """
        await self._init_db()
        await self._db_conn.execute(
            "INSERT INTO plugin_data (plugin, key, value) VALUES (?, ?, ?) "
            "ON CONFLICT(plugin, key) DO UPDATE SET value = excluded.value",
            (plugin, key, json.dumps(value)),
        )
        await self._db_conn.commit()

    async def get(self, plugin: str, key: str) -> Any:
        """
        异步获取数据。

        从数据库中获取指定插件和键名对应的值，
        返回的值会从 JSON 字符串反序列化为原始数据类型。

        Args:
            plugin: 插件标识符
            key: 数据键名

        Returns:
            Any: 存储的数据值，如果未找到则返回 None
        """
        await self._init_db()
        async with self._db_conn.execute(
            "SELECT value FROM plugin_data WHERE plugin = ? AND key = ?",
            (plugin, key),
        ) as cursor:
            row = await cursor.fetchone()
            return json.loads(row[0]) if row else None

    async def delete(self, plugin: str, key: str):
        """
        异步删除数据。

        从数据库中删除指定插件和键名对应的数据项。

        Args:
            plugin: 插件标识符
            key: 要删除的数据键名
        """
        await self._init_db()
        await self._db_conn.execute(
            "DELETE FROM plugin_data WHERE plugin = ? AND key = ?", (plugin, key)
        )
        await self._db_conn.commit()
