import aiosqlite
import os

DB_PATH = os.getenv("DB_PATH", "data/chat.db")


async def init_db():
    os.makedirs(os.path.dirname(DB_PATH), exist_ok=True)
    async with aiosqlite.connect(DB_PATH) as db:
        await db.executescript("""
            CREATE TABLE IF NOT EXISTS sessions (
                session_id   TEXT PRIMARY KEY,
                persona_id   TEXT DEFAULT 'default',
                created_at   DATETIME DEFAULT CURRENT_TIMESTAMP,
                updated_at   DATETIME DEFAULT CURRENT_TIMESTAMP,
                title        TEXT DEFAULT 'Новый чат',
                rpg_enabled  INTEGER DEFAULT 0,
                facts_json   TEXT DEFAULT '[]',
                global_plot  TEXT DEFAULT '',
                status_quo   TEXT DEFAULT '',
                plot_arc_json TEXT DEFAULT '{}',
                rng_seed     INTEGER
            );

            CREATE TABLE IF NOT EXISTS messages (
                id           INTEGER PRIMARY KEY AUTOINCREMENT,
                session_id   TEXT NOT NULL,
                role         TEXT NOT NULL,
                content      TEXT NOT NULL,
                created_at   DATETIME DEFAULT CURRENT_TIMESTAMP,
                FOREIGN KEY (session_id) REFERENCES sessions(session_id)
            );

            CREATE INDEX IF NOT EXISTS idx_messages_session
                ON messages(session_id);

            CREATE TABLE IF NOT EXISTS personas (
                persona_id       TEXT PRIMARY KEY,
                name             TEXT NOT NULL,
                emoji            TEXT DEFAULT '🤖',
                description      TEXT DEFAULT '',
                prompt           TEXT NOT NULL,
                custom           INTEGER DEFAULT 1,
                sd_enabled       INTEGER DEFAULT 0,
                lora_name        TEXT DEFAULT '',
                lora_weight      REAL DEFAULT 0.8,
                appearance_tags  TEXT DEFAULT '',
                personality      TEXT DEFAULT '',
                scenario         TEXT DEFAULT '',
                first_mes        TEXT DEFAULT '',
                mes_example      TEXT DEFAULT '',
                lorebook_json    TEXT DEFAULT '[]',
                avatar_path      TEXT DEFAULT ''
            );

            CREATE TABLE IF NOT EXISTS characters (
                card_id          TEXT PRIMARY KEY,
                name             TEXT NOT NULL,
                description      TEXT DEFAULT '',
                personality      TEXT DEFAULT '',
                scenario         TEXT DEFAULT '',
                first_mes        TEXT DEFAULT '',
                mes_example      TEXT DEFAULT '',
                raw_json         TEXT NOT NULL,
                lora_name        TEXT DEFAULT '',
                lora_weight      REAL DEFAULT 0.8,
                appearance_tags  TEXT DEFAULT '',
                lorebook_json    TEXT DEFAULT '[]',
                avatar_path      TEXT DEFAULT '',
                created_at       DATETIME DEFAULT CURRENT_TIMESTAMP
            );
        """)
        await _migrate_messages_columns(db)
        await _migrate_personas_columns(db)
        await _migrate_sessions_columns(db)
        await _migrate_characters_columns(db)
        await _migrate_rpg_quests(db)
        await _migrate_action_resolutions(db)
        await _migrate_state_snapshots(db)
        await db.commit()


async def _migrate_messages_columns(db):
    async with db.execute("PRAGMA table_info(messages)") as cur:
        cols = {row[1] for row in await cur.fetchall()}
    if "image_prompt" not in cols:
        await db.execute("ALTER TABLE messages ADD COLUMN image_prompt TEXT")
    if "image_path" not in cols:
        await db.execute("ALTER TABLE messages ADD COLUMN image_path TEXT")
    if "image_prompt_alt" not in cols:
        await db.execute("ALTER TABLE messages ADD COLUMN image_prompt_alt TEXT")
    if "image_path_alt" not in cols:
        await db.execute("ALTER TABLE messages ADD COLUMN image_path_alt TEXT")
    if "choices_json" not in cols:
        await db.execute("ALTER TABLE messages ADD COLUMN choices_json TEXT")


async def _migrate_personas_columns(db):
    async with db.execute("PRAGMA table_info(personas)") as cur:
        cols = {row[1] for row in await cur.fetchall()}
    if "personality" not in cols:
        await db.execute("ALTER TABLE personas ADD COLUMN personality TEXT DEFAULT ''")
    if "scenario" not in cols:
        await db.execute("ALTER TABLE personas ADD COLUMN scenario TEXT DEFAULT ''")
    if "first_mes" not in cols:
        await db.execute("ALTER TABLE personas ADD COLUMN first_mes TEXT DEFAULT ''")
    if "mes_example" not in cols:
        await db.execute("ALTER TABLE personas ADD COLUMN mes_example TEXT DEFAULT ''")
    if "lorebook_json" not in cols:
        await db.execute("ALTER TABLE personas ADD COLUMN lorebook_json TEXT DEFAULT '[]'")
    if "avatar_path" not in cols:
        await db.execute("ALTER TABLE personas ADD COLUMN avatar_path TEXT DEFAULT ''")
    if "alternate_greetings_json" not in cols:
        await db.execute("ALTER TABLE personas ADD COLUMN alternate_greetings_json TEXT DEFAULT '[]'")
    if "appearance_prose" not in cols:
        await db.execute("ALTER TABLE personas ADD COLUMN appearance_prose TEXT DEFAULT ''")


async def _migrate_sessions_columns(db):
    async with db.execute("PRAGMA table_info(sessions)") as cur:
        cols = {row[1] for row in await cur.fetchall()}
    if "rpg_enabled" not in cols:
        await db.execute("ALTER TABLE sessions ADD COLUMN rpg_enabled INTEGER DEFAULT 0")
    if "facts_json" not in cols:
        await db.execute("ALTER TABLE sessions ADD COLUMN facts_json TEXT DEFAULT '[]'")
    if "global_plot" not in cols:
        await db.execute("ALTER TABLE sessions ADD COLUMN global_plot TEXT DEFAULT ''")
    if "status_quo" not in cols:
        await db.execute("ALTER TABLE sessions ADD COLUMN status_quo TEXT DEFAULT ''")
    if "plot_arc_json" not in cols:
        await db.execute("ALTER TABLE sessions ADD COLUMN plot_arc_json TEXT DEFAULT '{}'")
    if "rng_seed" not in cols:
        await db.execute("ALTER TABLE sessions ADD COLUMN rng_seed INTEGER")
    if "affinity" not in cols:
        await db.execute("ALTER TABLE sessions ADD COLUMN affinity INTEGER DEFAULT 0")
    if "genre" not in cols:
        await db.execute("ALTER TABLE sessions ADD COLUMN genre TEXT DEFAULT 'adventure'")
    if "rpg_settings_json" not in cols:
        await db.execute("ALTER TABLE sessions ADD COLUMN rpg_settings_json TEXT DEFAULT '{}'")
    if "outfit_json" not in cols:
        await db.execute("ALTER TABLE sessions ADD COLUMN outfit_json TEXT DEFAULT '[]'")
    if "scene_json" not in cols:
        await db.execute("ALTER TABLE sessions ADD COLUMN scene_json TEXT DEFAULT '{}'")
    if "narrative_stats_json" not in cols:
        await db.execute(
            "ALTER TABLE sessions ADD COLUMN narrative_stats_json TEXT DEFAULT "
            "'{\"lust\":0,\"stamina\":10,\"tension\":0}'"
        )

async def _migrate_rpg_quests(db):
    await db.executescript("""
        CREATE TABLE IF NOT EXISTS rpg_quests (
            id INTEGER PRIMARY KEY AUTOINCREMENT,
            session_id TEXT NOT NULL,
            title TEXT NOT NULL,
            status TEXT DEFAULT 'active',
            created_at DATETIME DEFAULT CURRENT_TIMESTAMP
        );
        CREATE INDEX IF NOT EXISTS idx_rpg_quests_session ON rpg_quests(session_id);
    """)


async def _migrate_action_resolutions(db):
    await db.executescript(
        """
        CREATE TABLE IF NOT EXISTS action_resolutions (
            id INTEGER PRIMARY KEY AUTOINCREMENT,
            session_id TEXT NOT NULL,
            message_id INTEGER,
            intent_text TEXT NOT NULL,
            roll INTEGER NOT NULL,
            outcome TEXT NOT NULL,
            resolution_text TEXT NOT NULL,
            created_at DATETIME DEFAULT CURRENT_TIMESTAMP
        );
        CREATE INDEX IF NOT EXISTS idx_action_resolutions_session
            ON action_resolutions(session_id);
        """
    )


async def _migrate_state_snapshots(db):
    await db.executescript(
        """
        CREATE TABLE IF NOT EXISTS session_state_snapshots (
            message_id INTEGER PRIMARY KEY,
            session_id TEXT NOT NULL,
            facts_json TEXT NOT NULL DEFAULT '[]',
            global_plot TEXT NOT NULL DEFAULT '',
            status_quo TEXT NOT NULL DEFAULT '',
            plot_arc_json TEXT NOT NULL DEFAULT '{}',
            affinity INTEGER NOT NULL DEFAULT 0,
            outfit_json TEXT NOT NULL DEFAULT '[]',
            scene_json TEXT NOT NULL DEFAULT '{}',
            narrative_stats_json TEXT NOT NULL DEFAULT '{"lust":0,"stamina":10,"tension":0}',
            quests_json TEXT NOT NULL DEFAULT '[]',
            action_resolutions_json TEXT NOT NULL DEFAULT '[]',
            created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
            FOREIGN KEY (message_id) REFERENCES messages(id) ON DELETE CASCADE
        );
        CREATE INDEX IF NOT EXISTS idx_state_snapshots_session
            ON session_state_snapshots(session_id);
        """
    )


async def _migrate_characters_columns(db):
    async with db.execute("PRAGMA table_info(characters)") as cur:
        cols = {row[1] for row in await cur.fetchall()}
    if "avatar_path" not in cols:
        await db.execute("ALTER TABLE characters ADD COLUMN avatar_path TEXT DEFAULT ''")
    if "alternate_greetings_json" not in cols:
        await db.execute("ALTER TABLE characters ADD COLUMN alternate_greetings_json TEXT DEFAULT '[]'")
    if "appearance_prose" not in cols:
        await db.execute("ALTER TABLE characters ADD COLUMN appearance_prose TEXT DEFAULT ''")
