import sqlite3
import json
from pathlib import Path
from typing import List, Optional
from .base import MessageStorage
from ..message import Message

class SQLiteStorage(MessageStorage):
    """
    基于SQLite3的存储实现
    是现阶段的默认实现方式
    后面将会扩展有关其他数据库的接口，或在chatroom文件里面选择使用的接口（兼容多接口）或使用类似于函数指针的东西转接
    """
    """基本信息与初始化"""
    def __init__(self, db_dir:str = "./data"):
        """
        Args:
            db_dir: 文件数据库目录，默认是本目录下新建data目录以实现专门存储
        """
        self.db_dir = Path(db_dir) # 系统路径寻找
        self.db_dir.mkdir(parents=True, exist_ok=True) # 存在路径或创建路径
        self._connections={} # 已经获取连接的房间
        
    def _get_db_path(self, roomid: str) -> str:
        """获取房间对应的数据库文件路径"""
        return str(self.db_dir / f"{roomid}.db")
    
    def _get_connect(self, roomid: str):
        """获取或创建数据库连接"""
        if roomid not in self._connections:
            db_path = self._get_db_path(roomid)
            conn = sqlite3.connect(db_path)
            conn.row_factory = sqlite3.Row
            self._connections[roomid] = conn
            self._init_tables(conn)
        return self._connections[roomid]
        
    def _init_tables(self, conn: sqlite3.Connection):
        """如果未建表，则初始化表格，每次初次连接都建议初始化表格"""
        cursor = conn.cursor()
        
        # 创建消息表
        cursor.execute("""
            CREATE TABLE IF NOT EXISTS messages (
                id TEXT PRIMARY KEY,
                sendid TEXT NOT NULL,
                sendname TEXT NOT NULL,
                content TEXT NOT NULL,
                msgtype TEXT DEFAULT 'text',
                timestamp INTEGER NOT NULL,
                replyto TEXT,
                roomid TEXT NOT NULL,
                others TEXT DEFAULT '{}'
            )
        """) # 对应消息对象
        
        # 创建索引
        cursor.execute("""
            CREATE INDEX IF NOT EXISTS idx_timestamp 
            ON messages(timestamp DESC)
        """)
        
        cursor.execute("""
            CREATE INDEX IF NOT EXISTS idx_sender 
            ON messages(sendid)
        """)
        
        cursor.execute("""
            CREATE INDEX IF NOT EXISTS idx_room 
            ON messages(roomid)
        """)
        
        cursor.execute("""
            CREATE INDEX IF NOT EXISTS idx_reply_to 
            ON messages(replyto)
        """)
        
        conn.commit()
        
    """添加"""
    def add(self, message: Message) -> bool:
        """添加到数据库消息"""
        conn = self._get_connect(message.room_id)
        cursor = conn.cursor()
        
        try:
            cursor.execute("""
                INSERT INTO messages 
                (id, sendid, sendname, content, msgtype, timestamp, replyto, roomid, others)
                VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)
            """, (
                message._id,
                message.sender_id,
                message.sender_name,
                message.content,
                message.msg_type,
                message.timestamp,
                message.reply_to,
                message.room_id,
                json.dumps(message.metadata)
            ))
            conn.commit()
            return True
        except sqlite3.Error:
            return False
    
    """获取信息存储"""
    def get_recent(self, roomid: str, limit: int = 100, before: Optional[int] = None) -> List[Message]:
        """获取最近N条消息"""
        conn = self._get_connect(roomid)
        cursor = conn.cursor()
        
        if before:
            cursor.execute("""
                SELECT * FROM messages 
                WHERE roomid = ? AND timestamp < ?
                ORDER BY timestamp DESC 
                LIMIT ?
            """, (roomid, before, limit))
        else:
            cursor.execute("""
                SELECT * FROM messages 
                WHERE roomid = ?
                ORDER BY timestamp DESC 
                LIMIT ?
            """, (roomid, limit))
        
        rows = cursor.fetchall()
        return [self._row_to_message(row) for row in reversed(rows)]
    
    def get_by_id(self, msg_id: str) -> Optional[Message]:
        """根据ID获取消息"""
        for roomid, conn in self._connections.items():
            cursor = conn.cursor()
            cursor.execute("SELECT * FROM messages WHERE id = ?", (msg_id,))
            row = cursor.fetchone()
            if row:
                return self._row_to_message(row)
        return None
    
    def get_by_sender(self, roomid: str, sender_id: str, limit: int = 100) -> List[Message]:
        """获取特定发送者的消息"""
        conn = self._get_connect(roomid)
        cursor = conn.cursor()
        
        cursor.execute("""
            SELECT * FROM messages 
            WHERE roomid = ? AND sendid = ?
            ORDER BY timestamp DESC 
            LIMIT ?
        """, (roomid, sender_id, limit))
        
        rows = cursor.fetchall()
        return [self._row_to_message(row) for row in reversed(rows)]
    
    def get_replies(self, roomid: str, reply_to: str, limit: int = 50) -> List[Message]:
        """获取某条消息的回复"""
        conn = self._get_connect(roomid)
        cursor = conn.cursor()
        
        cursor.execute("""
            SELECT * FROM messages 
            WHERE roomid = ? AND replyto = ?
            ORDER BY timestamp ASC 
            LIMIT ?
        """, (roomid, reply_to, limit))
        
        rows = cursor.fetchall()
        return [self._row_to_message(row) for row in rows]
    
    """删除信息存储"""
    def delete(self, msg_id: str) -> bool:
        """根据消息ID删除单条消息"""
        for roomid, conn in self._connections.items():
            cursor = conn.cursor()
            try:
                cursor.execute("DELETE FROM messages WHERE id = ?", (msg_id,))
                conn.commit()
                if cursor.rowcount > 0:
                    return True
            except sqlite3.Error:
                return False
        return False


    def delete_by_sender(self, roomid: str, sender_id: str) -> int:
        """删除指定发送者的所有消息，返回删除数量"""
        conn = self._get_connect(roomid)
        cursor = conn.cursor()
        
        try:
            cursor.execute("DELETE FROM messages WHERE roomid = ? AND sendid = ?", (roomid, sender_id))
            conn.commit()
            return cursor.rowcount
        except sqlite3.Error:
            return 0


    def delete_all(self, roomid: str) -> int:
        """删除指定房间的所有消息，返回删除数量"""
        conn = self._get_connect(roomid)
        cursor = conn.cursor()
        
        try:
            cursor.execute("DELETE FROM messages WHERE roomid = ?", (roomid,))
            conn.commit()
            return cursor.rowcount
        except sqlite3.Error:
            return 0
    
    def clear(self, roomid: str):
        """清空指定房间的消息"""
        conn = self._get_connect(roomid)
        cursor = conn.cursor()
        cursor.execute("DELETE FROM messages WHERE roomid = ?", (roomid,))
        conn.commit()
    
    """其他处理"""
    def count(self, roomid: str) -> int:
        """获取消息总数"""
        conn = self._get_connect(roomid)
        cursor = conn.cursor()
        cursor.execute("SELECT COUNT(*) FROM messages WHERE roomid = ?", (roomid,))
        return cursor.fetchone()[0]
    
    def close(self):
        """关闭所有数据库连接"""
        for conn in self._connections.values():
            conn.close()
        self._connections.clear()
    
    def close_room(self, roomid: str):
        """关闭特定房间的连接"""
        if roomid in self._connections:
            self._connections[roomid].close()
            del self._connections[roomid]
    
    def _row_to_message(self, row) -> Message:
        """数据库行转Message对象"""
        return Message(
            _id=row['id'],
            sender_id=row['sendid'],
            sender_name=row['sendname'],
            content=row['content'],
            msg_type=row['msgtype'],
            timestamp=row['timestamp'],
            reply_to=row['replyto'],
            room_id=row['roomid'],
            metadata=json.loads(row['others']) if row['others'] else {}
        )
    
    def get_db_path(self, roomid: str) -> str:
        """获取数据库文件路径"""
        return self._get_db_path(roomid)
    
    def clear_all(self):
        """清空所有数据库文件"""
        # 关闭所有数据库连接
        self.close()
        # 删除 data 目录中的所有数据库文件
        import shutil
        if self.db_dir.exists():
            shutil.rmtree(self.db_dir)
        # 重新创建 data 目录
        self.db_dir.mkdir(parents=True, exist_ok=True)
    