import time

import aiosqlite
from cryptography.fernet import Fernet

import config

_fernet = None

DEFAULT_START = "⌯ اسف حب، هذا البوت خاص بالمطور فقط."


def _f():
    global _fernet
    if _fernet is None:
        _fernet = Fernet(config.FERNET_KEY.encode())
    return _fernet


def encrypt(value):
    return _f().encrypt(value.encode()).decode()


def decrypt(value):
    return _f().decrypt(value.encode()).decode()


async def init_db():
    async with aiosqlite.connect(config.DB_PATH) as conn:
        await conn.execute("PRAGMA journal_mode=WAL")
        await conn.execute(
            """CREATE TABLE IF NOT EXISTS accounts (
                user_id INTEGER PRIMARY KEY,
                phone TEXT,
                name TEXT,
                username TEXT,
                session TEXT NOT NULL,
                added_at INTEGER
            )"""
        )
        await conn.execute(
            """CREATE TABLE IF NOT EXISTS devs (
                user_id INTEGER PRIMARY KEY,
                username TEXT,
                added_at INTEGER
            )"""
        )
        await conn.execute(
            """CREATE TABLE IF NOT EXISTS settings (
                key TEXT PRIMARY KEY,
                value TEXT
            )"""
        )
        for dev in config.DEV_ID:
            await conn.execute(
                "INSERT OR IGNORE INTO devs (user_id, username, added_at) VALUES (?, ?, ?)",
                (dev, None, int(time.time())),
            )
        await conn.execute(
            "INSERT OR IGNORE INTO settings (key, value) VALUES (?, ?)",
            ("start_message", DEFAULT_START),
        )
        await conn.commit()


async def save_account(user_id, phone, name, username, session_string):
    async with aiosqlite.connect(config.DB_PATH) as conn:
        await conn.execute(
            """INSERT INTO accounts (user_id, phone, name, username, session, added_at)
               VALUES (?, ?, ?, ?, ?, ?)
               ON CONFLICT(user_id) DO UPDATE SET
                 phone=excluded.phone,
                 name=excluded.name,
                 username=excluded.username,
                 session=excluded.session""",
            (user_id, phone, name, username, encrypt(session_string), int(time.time())),
        )
        await conn.commit()


async def get_accounts():
    async with aiosqlite.connect(config.DB_PATH) as conn:
        conn.row_factory = aiosqlite.Row
        cur = await conn.execute("SELECT * FROM accounts ORDER BY added_at ASC")
        rows = await cur.fetchall()
        return [dict(r) for r in rows]


async def get_account(user_id):
    async with aiosqlite.connect(config.DB_PATH) as conn:
        conn.row_factory = aiosqlite.Row
        cur = await conn.execute("SELECT * FROM accounts WHERE user_id = ?", (user_id,))
        row = await cur.fetchone()
        return dict(row) if row else None


async def get_session(user_id):
    row = await get_account(user_id)
    return decrypt(row["session"]) if row else None


async def delete_account(user_id):
    async with aiosqlite.connect(config.DB_PATH) as conn:
        await conn.execute("DELETE FROM accounts WHERE user_id = ?", (user_id,))
        await conn.commit()


async def count_accounts():
    async with aiosqlite.connect(config.DB_PATH) as conn:
        cur = await conn.execute("SELECT COUNT(*) FROM accounts")
        row = await cur.fetchone()
        return row[0]


async def add_dev(user_id, username=None):
    async with aiosqlite.connect(config.DB_PATH) as conn:
        await conn.execute(
            """INSERT INTO devs (user_id, username, added_at) VALUES (?, ?, ?)
               ON CONFLICT(user_id) DO UPDATE SET username=excluded.username""",
            (user_id, username, int(time.time())),
        )
        await conn.commit()


async def delete_dev(user_id):
    async with aiosqlite.connect(config.DB_PATH) as conn:
        await conn.execute("DELETE FROM devs WHERE user_id = ?", (user_id,))
        await conn.commit()


async def get_devs():
    async with aiosqlite.connect(config.DB_PATH) as conn:
        conn.row_factory = aiosqlite.Row
        cur = await conn.execute("SELECT * FROM devs ORDER BY added_at ASC")
        rows = await cur.fetchall()
        return [dict(r) for r in rows]


async def is_dev(user_id):
    async with aiosqlite.connect(config.DB_PATH) as conn:
        cur = await conn.execute("SELECT 1 FROM devs WHERE user_id = ?", (user_id,))
        return await cur.fetchone() is not None


async def get_setting(key, default=None):
    async with aiosqlite.connect(config.DB_PATH) as conn:
        cur = await conn.execute("SELECT value FROM settings WHERE key = ?", (key,))
        row = await cur.fetchone()
        return row[0] if row else default


async def set_setting(key, value):
    async with aiosqlite.connect(config.DB_PATH) as conn:
        await conn.execute(
            """INSERT INTO settings (key, value) VALUES (?, ?)
               ON CONFLICT(key) DO UPDATE SET value=excluded.value""",
            (key, value),
        )
        await conn.commit()
