import asyncio
import sqlite3
from datetime import datetime
from pathlib import Path
from typing import Optional

from .models import Room, RoomState, RaceResult
from .config import Config


class RoomStore:
    def __init__(self, config: Config):
        self.config = config
        self.rooms: dict[str, Room] = {}
        self._locks: dict[str, asyncio.Lock] = {}
        self.db_path = Path(config.RACE_DB_FILE)
        self.db_path.parent.mkdir(parents=True, exist_ok=True)
        self._init_db()

    def _init_db(self):
        """Initialize database tables."""
        conn = sqlite3.connect(self.db_path)
        cursor = conn.cursor()

        cursor.execute("""
            CREATE TABLE IF NOT EXISTS room_snapshots (
                scope TEXT PRIMARY KEY,
                state TEXT NOT NULL,
                created_at TEXT NOT NULL,
                horses TEXT NOT NULL,
                bets TEXT NOT NULL,
                champion_name TEXT,
                tick_count INTEGER DEFAULT 0
            )
        """)

        cursor.execute("""
            CREATE TABLE IF NOT EXISTS race_history (
                race_id TEXT PRIMARY KEY,
                scope TEXT NOT NULL,
                champion_name TEXT NOT NULL,
                champion_owner TEXT NOT NULL,
                participants TEXT NOT NULL,
                bet_distribution TEXT NOT NULL,
                duration_ticks INTEGER NOT NULL,
                completed_at TEXT NOT NULL
            )
        """)

        cursor.execute("""
            CREATE TABLE IF NOT EXISTS user_horse_names (
                user_id TEXT PRIMARY KEY,
                horse_name TEXT NOT NULL
            )
        """)

        conn.commit()
        conn.close()

    def get_lock(self, scope: str) -> asyncio.Lock:
        """Get or create per-room lock."""
        if scope not in self._locks:
            self._locks[scope] = asyncio.Lock()
        return self._locks[scope]

    def get_room(self, scope: str) -> Optional[Room]:
        """Get room by scope."""
        return self.rooms.get(scope)

    def create_room(self, scope: str) -> Room:
        """Create new room."""
        room = Room(scope=scope)
        self.rooms[scope] = room
        self._save_snapshot(room)
        return room

    def delete_room(self, scope: str):
        """Delete room."""
        if scope in self.rooms:
            del self.rooms[scope]

    def get_last_horse_name(self, user_id: str) -> Optional[str]:
        conn = sqlite3.connect(self.db_path)
        cursor = conn.cursor()
        cursor.execute("SELECT horse_name FROM user_horse_names WHERE user_id = ?", (user_id,))
        row = cursor.fetchone()
        conn.close()
        return row[0] if row else None

    def set_last_horse_name(self, user_id: str, horse_name: str):
        conn = sqlite3.connect(self.db_path)
        cursor = conn.cursor()
        cursor.execute(
            "INSERT OR REPLACE INTO user_horse_names (user_id, horse_name) VALUES (?, ?)",
            (user_id, horse_name),
        )
        conn.commit()
        conn.close()

    def _save_snapshot(self, room: Room):
        """Save room snapshot to database."""
        import json

        horses_json = json.dumps({
            name: {
                "owner_id": horse.owner_id,
                "name": horse.name,
                "index": horse.index,
                "position": horse.position,
                "state": horse.state.value,
            }
            for name, horse in room.horses.items()
        })

        bets_json = json.dumps([
            {
                "user_id": bet.user_id,
                "horse_name": bet.horse_name,
                "amount": bet.amount,
            }
            for bet in room.bets
        ])

        conn = sqlite3.connect(self.db_path)
        cursor = conn.cursor()
        cursor.execute("""
            INSERT OR REPLACE INTO room_snapshots
            (scope, state, created_at, horses, bets, champion_name, tick_count)
            VALUES (?, ?, ?, ?, ?, ?, ?)
        """, (
            room.scope,
            room.state.value,
            room.created_at.isoformat(),
            horses_json,
            bets_json,
            room.champion_name,
            room.tick_count,
        ))
        conn.commit()
        conn.close()

    def save_race_result(self, result: RaceResult):
        """Save race result to history."""
        import json

        conn = sqlite3.connect(self.db_path)
        cursor = conn.cursor()
        cursor.execute("""
            INSERT INTO race_history
            (race_id, scope, champion_name, champion_owner, participants, bet_distribution, duration_ticks, completed_at)
            VALUES (?, ?, ?, ?, ?, ?, ?, ?)
        """, (
            result.race_id,
            result.scope,
            result.champion_name,
            result.champion_owner,
            json.dumps(result.participants),
            json.dumps(result.bet_distribution),
            result.duration_ticks,
            result.completed_at.isoformat(),
        ))
        conn.commit()
        conn.close()
