#!/usr/bin/env python3
"""
Database layer for videobot payment system.

SQLite database with:
- Users table (balances, promo eligibility)
- Transactions table (comprehensive audit log)
- Promo config table (global settings)

Separate databases for dev/prod environments.
"""

import os
import sqlite3
from contextlib import contextmanager
from datetime import datetime
from pathlib import Path
from typing import Optional, Dict, List, Any

# Base path for databases
NFS_BASE = Path(os.environ.get("NFS_BASE", "/mnt/video"))

# Shared showcase database (used by both dev and prod)
SHOWCASE_DB_PATH = NFS_BASE / "showcase.db"


def get_db_path(source: Optional[str] = None) -> Path:
    """
    Get database path based on environment.

    Args:
        source: 'dev' or 'prod'. If None, uses BUILD_SOURCE env var.

    Returns:
        Path to SQLite database file.
    """
    if source is None:
        source = os.environ.get("BUILD_SOURCE", "dev")

    # Allow override via DB_PATH env var
    if os.environ.get("DB_PATH"):
        return Path(os.environ["DB_PATH"])

    return NFS_BASE / f"videobot_{source}.db"


@contextmanager
def get_connection(db_path: Optional[Path] = None):
    """
    Context manager for database connections.

    Args:
        db_path: Optional path to database. Uses get_db_path() if None.

    Yields:
        sqlite3.Connection with row_factory set to sqlite3.Row
    """
    if db_path is None:
        db_path = get_db_path()

    conn = sqlite3.connect(str(db_path))
    conn.row_factory = sqlite3.Row
    try:
        yield conn
        conn.commit()
    except Exception:
        conn.rollback()
        raise
    finally:
        conn.close()


def init_db(db_path: Optional[Path] = None) -> None:
    """
    Initialize database schema.

    Creates tables if they don't exist.
    """
    if db_path is None:
        db_path = get_db_path()

    print(f"Initializing database: {db_path}")

    with get_connection(db_path) as conn:
        cursor = conn.cursor()

        # Users table
        cursor.execute("""
            CREATE TABLE IF NOT EXISTS users (
                user_id INTEGER PRIMARY KEY,
                username TEXT,
                first_name TEXT,
                last_name TEXT,
                balance INTEGER DEFAULT 0,
                total_purchased INTEGER DEFAULT 0,
                total_spent INTEGER DEFAULT 0,
                is_promo_eligible INTEGER DEFAULT 0,
                promo_purchases INTEGER DEFAULT 0,
                is_blocked INTEGER DEFAULT 0,
                created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
                updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
            )
        """)

        # Promo config table
        cursor.execute("""
            CREATE TABLE IF NOT EXISTS promo_config (
                key TEXT PRIMARY KEY,
                value TEXT NOT NULL
            )
        """)

        # Initialize promo_users_remaining if not exists
        cursor.execute("""
            INSERT OR IGNORE INTO promo_config (key, value)
            VALUES ('promo_users_remaining', '100')
        """)

        # Giveaway config table (separate from promo)
        cursor.execute("""
            CREATE TABLE IF NOT EXISTS giveaway_config (
                key TEXT PRIMARY KEY,
                value TEXT NOT NULL
            )
        """)

        # Initialize giveaway config with defaults
        cursor.execute("""
            INSERT OR IGNORE INTO giveaway_config (key, value)
            VALUES
                ('active', '0'),
                ('tokens_per_user', '3'),
                ('remaining_users', '0'),
                ('started_at', ''),
                ('started_by', '')
        """)

        # Transactions table (comprehensive audit log)
        cursor.execute("""
            CREATE TABLE IF NOT EXISTS transactions (
                id INTEGER PRIMARY KEY AUTOINCREMENT,
                user_id INTEGER NOT NULL,
                amount INTEGER NOT NULL,
                balance_before INTEGER NOT NULL,
                balance_after INTEGER NOT NULL,
                type TEXT NOT NULL,
                description TEXT,
                telegram_payment_charge_id TEXT,
                provider_payment_charge_id TEXT,
                amount_rub INTEGER,
                currency TEXT,
                task_id TEXT,
                product_id TEXT,
                initiated_by INTEGER,
                ip_address TEXT,
                created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
                FOREIGN KEY (user_id) REFERENCES users(user_id)
            )
        """)

        # Indexes for fast lookups
        cursor.execute("""
            CREATE INDEX IF NOT EXISTS idx_transactions_user_id
            ON transactions(user_id)
        """)
        cursor.execute("""
            CREATE INDEX IF NOT EXISTS idx_transactions_type
            ON transactions(type)
        """)
        cursor.execute("""
            CREATE INDEX IF NOT EXISTS idx_transactions_created_at
            ON transactions(created_at)
        """)
        cursor.execute("""
            CREATE INDEX IF NOT EXISTS idx_transactions_task_id
            ON transactions(task_id)
        """)

        # Migration: Add terms columns if not exists
        cursor.execute("PRAGMA table_info(users)")
        columns = [col[1] for col in cursor.fetchall()]
        if "terms_accepted_at" not in columns:
            cursor.execute("""
                ALTER TABLE users ADD COLUMN terms_accepted_at TIMESTAMP DEFAULT NULL
            """)
            print("Added terms_accepted_at column to users table")
        if "terms_version" not in columns:
            cursor.execute("""
                ALTER TABLE users ADD COLUMN terms_version INTEGER DEFAULT 0
            """)
            print("Added terms_version column to users table")

        # Migration: Add giveaway_received column if not exists
        if "giveaway_received" not in columns:
            cursor.execute("""
                ALTER TABLE users ADD COLUMN giveaway_received INTEGER DEFAULT 0
            """)
            print("Added giveaway_received column to users table")

        # Migration: Add ref_source column if not exists
        if "ref_source" not in columns:
            cursor.execute("ALTER TABLE users ADD COLUMN ref_source TEXT DEFAULT NULL")
            print("Added ref_source column to users table")

        # Migration: Add gift_pack_received column if not exists
        if "gift_pack_received" not in columns:
            cursor.execute("""
                ALTER TABLE users ADD COLUMN gift_pack_received INTEGER DEFAULT 0
            """)
            print("Added gift_pack_received column to users table")

        # Gift packs table
        cursor.execute("""
            CREATE TABLE IF NOT EXISTS gift_packs (
                id INTEGER PRIMARY KEY AUTOINCREMENT,
                user_id INTEGER NOT NULL,
                tokens INTEGER NOT NULL,
                status TEXT NOT NULL DEFAULT 'active',
                expires_at TIMESTAMP NOT NULL,
                created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
                redeemed_at TIMESTAMP DEFAULT NULL,
                expired_at TIMESTAMP DEFAULT NULL,
                notified_at TIMESTAMP DEFAULT NULL,
                campaign_id TEXT DEFAULT NULL,
                description TEXT DEFAULT NULL,
                created_by INTEGER DEFAULT NULL,
                FOREIGN KEY (user_id) REFERENCES users(user_id)
            )
        """)

        cursor.execute("""
            CREATE INDEX IF NOT EXISTS idx_gift_packs_user_status
                ON gift_packs(user_id, status)
        """)
        cursor.execute("""
            CREATE INDEX IF NOT EXISTS idx_gift_packs_expires_at
                ON gift_packs(expires_at)
        """)
        cursor.execute("""
            CREATE INDEX IF NOT EXISTS idx_gift_packs_campaign_id
                ON gift_packs(campaign_id)
        """)

        # Gift pack campaigns table
        cursor.execute("""
            CREATE TABLE IF NOT EXISTS gift_pack_campaigns (
                id INTEGER PRIMARY KEY AUTOINCREMENT,
                campaign_type TEXT NOT NULL,
                ref_source TEXT DEFAULT NULL,
                tokens INTEGER NOT NULL DEFAULT 3,
                expiration_days INTEGER NOT NULL DEFAULT 7,
                remaining_slots INTEGER DEFAULT -1,
                is_active INTEGER DEFAULT 1,
                description TEXT DEFAULT NULL,
                created_by INTEGER DEFAULT NULL,
                created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
            )
        """)

        # Survey tables
        cursor.execute("""
            CREATE TABLE IF NOT EXISTS surveys (
                id INTEGER PRIMARY KEY AUTOINCREMENT,
                title TEXT NOT NULL,
                questions_json TEXT NOT NULL,
                reward_tokens INTEGER NOT NULL DEFAULT 3,
                reward_days INTEGER NOT NULL DEFAULT 7,
                is_active INTEGER DEFAULT 1,
                created_by INTEGER,
                created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
            )
        """)

        cursor.execute("""
            CREATE TABLE IF NOT EXISTS survey_invitations (
                id INTEGER PRIMARY KEY AUTOINCREMENT,
                survey_id INTEGER NOT NULL,
                user_id INTEGER NOT NULL,
                status TEXT NOT NULL DEFAULT 'sent',
                sent_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
                started_at TIMESTAMP,
                completed_at TIMESTAMP,
                rewarded INTEGER DEFAULT 0,
                UNIQUE(survey_id, user_id)
            )
        """)
        cursor.execute("""
            CREATE INDEX IF NOT EXISTS idx_survey_inv_status
            ON survey_invitations(status)
        """)

        cursor.execute("""
            CREATE TABLE IF NOT EXISTS survey_responses (
                id INTEGER PRIMARY KEY AUTOINCREMENT,
                invitation_id INTEGER NOT NULL,
                survey_id INTEGER NOT NULL,
                user_id INTEGER NOT NULL,
                question_key TEXT NOT NULL,
                answer_value TEXT NOT NULL,
                created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
                UNIQUE(invitation_id, question_key)
            )
        """)
        cursor.execute("""
            CREATE INDEX IF NOT EXISTS idx_survey_resp_survey
            ON survey_responses(survey_id)
        """)

        conn.commit()
        print("Database initialized successfully")


# =============================================================================
# User Operations
# =============================================================================

def get_user(user_id: int, db_path: Optional[Path] = None) -> Optional[Dict[str, Any]]:
    """Get user by ID."""
    with get_connection(db_path) as conn:
        cursor = conn.cursor()
        cursor.execute("SELECT * FROM users WHERE user_id = ?", (user_id,))
        row = cursor.fetchone()
        return dict(row) if row else None


def get_or_create_user(
    user_id: int,
    username: Optional[str] = None,
    first_name: Optional[str] = None,
    last_name: Optional[str] = None,
    ref_source: Optional[str] = None,
    db_path: Optional[Path] = None
) -> Dict[str, Any]:
    """
    Get existing user or create new one.

    Args:
        ref_source: Referral source tag from deep link (only saved on first create).

    Returns:
        User dict with all fields.
    """
    with get_connection(db_path) as conn:
        cursor = conn.cursor()

        # Try to get existing user
        cursor.execute("SELECT * FROM users WHERE user_id = ?", (user_id,))
        row = cursor.fetchone()

        if row:
            # Update username/name if changed (never overwrite ref_source)
            if username or first_name or last_name:
                cursor.execute("""
                    UPDATE users
                    SET username = COALESCE(?, username),
                        first_name = COALESCE(?, first_name),
                        last_name = COALESCE(?, last_name),
                        updated_at = CURRENT_TIMESTAMP
                    WHERE user_id = ?
                """, (username, first_name, last_name, user_id))
                cursor.execute("SELECT * FROM users WHERE user_id = ?", (user_id,))
                row = cursor.fetchone()
            return dict(row)

        # Create new user
        # All new users are promo-eligible by default
        # Promo availability is controlled by promo_users_remaining counter
        # User loses eligibility only after using promo (making a promo purchase)
        cursor.execute("""
            INSERT INTO users (user_id, username, first_name, last_name, is_promo_eligible, ref_source)
            VALUES (?, ?, ?, ?, 1, ?)
        """, (user_id, username, first_name, last_name, ref_source))

        cursor.execute("SELECT * FROM users WHERE user_id = ?", (user_id,))
        return dict(cursor.fetchone())


def update_user(
    user_id: int,
    updates: Dict[str, Any],
    db_path: Optional[Path] = None
) -> bool:
    """
    Update user fields.

    Args:
        user_id: User ID
        updates: Dict of field names to new values

    Returns:
        True if user was updated.
    """
    if not updates:
        return False

    # Build SET clause
    set_parts = []
    values = []
    for key, value in updates.items():
        set_parts.append(f"{key} = ?")
        values.append(value)

    set_parts.append("updated_at = CURRENT_TIMESTAMP")
    values.append(user_id)

    with get_connection(db_path) as conn:
        cursor = conn.cursor()
        cursor.execute(
            f"UPDATE users SET {', '.join(set_parts)} WHERE user_id = ?",
            values
        )
        return cursor.rowcount > 0


def get_accepted_terms_version(user_id: int, db_path: Optional[Path] = None) -> int:
    """Get the version of terms the user has accepted (0 if never accepted)."""
    with get_connection(db_path) as conn:
        cursor = conn.cursor()
        cursor.execute(
            "SELECT terms_version FROM users WHERE user_id = ?",
            (user_id,)
        )
        row = cursor.fetchone()
        if row and row["terms_version"]:
            return row["terms_version"]
        return 0


def accept_terms(user_id: int, version: int, db_path: Optional[Path] = None) -> bool:
    """
    Record user's acceptance of terms of service.

    Args:
        user_id: User ID
        version: Terms version being accepted

    Returns:
        True if updated successfully.
    """
    with get_connection(db_path) as conn:
        cursor = conn.cursor()
        cursor.execute(
            "UPDATE users SET terms_accepted_at = CURRENT_TIMESTAMP, terms_version = ? WHERE user_id = ?",
            (version, user_id)
        )
        return cursor.rowcount > 0


def get_all_users(
    limit: int = 100,
    offset: int = 0,
    order_by: str = "created_at DESC",
    db_path: Optional[Path] = None
) -> List[Dict[str, Any]]:
    """Get all users with pagination."""
    with get_connection(db_path) as conn:
        cursor = conn.cursor()
        cursor.execute(
            f"SELECT * FROM users ORDER BY {order_by} LIMIT ? OFFSET ?",
            (limit, offset)
        )
        return [dict(row) for row in cursor.fetchall()]


def get_users_count(db_path: Optional[Path] = None) -> int:
    """Get total number of users."""
    with get_connection(db_path) as conn:
        cursor = conn.cursor()
        cursor.execute("SELECT COUNT(*) as count FROM users")
        return cursor.fetchone()["count"]


def search_users(
    query: str,
    limit: int = 20,
    db_path: Optional[Path] = None
) -> List[Dict[str, Any]]:
    """Search users by username, name, or ID."""
    with get_connection(db_path) as conn:
        cursor = conn.cursor()

        # Try to parse as user_id
        try:
            user_id = int(query)
            cursor.execute(
                "SELECT * FROM users WHERE user_id = ? LIMIT ?",
                (user_id, limit)
            )
        except ValueError:
            # Search by username or name
            pattern = f"%{query}%"
            cursor.execute("""
                SELECT * FROM users
                WHERE username LIKE ? OR first_name LIKE ? OR last_name LIKE ?
                ORDER BY created_at DESC
                LIMIT ?
            """, (pattern, pattern, pattern, limit))

        return [dict(row) for row in cursor.fetchall()]


# =============================================================================
# Transaction Operations
# =============================================================================

def create_transaction(
    user_id: int,
    amount: int,
    balance_before: int,
    balance_after: int,
    txn_type: str,
    description: Optional[str] = None,
    telegram_payment_charge_id: Optional[str] = None,
    provider_payment_charge_id: Optional[str] = None,
    amount_rub: Optional[int] = None,
    currency: Optional[str] = None,
    task_id: Optional[str] = None,
    product_id: Optional[str] = None,
    initiated_by: Optional[int] = None,
    db_path: Optional[Path] = None
) -> int:
    """
    Create a transaction record.

    Returns:
        Transaction ID.
    """
    with get_connection(db_path) as conn:
        cursor = conn.cursor()
        cursor.execute("""
            INSERT INTO transactions (
                user_id, amount, balance_before, balance_after, type,
                description, telegram_payment_charge_id, provider_payment_charge_id,
                amount_rub, currency, task_id, product_id, initiated_by
            ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
        """, (
            user_id, amount, balance_before, balance_after, txn_type,
            description, telegram_payment_charge_id, provider_payment_charge_id,
            amount_rub, currency, task_id, product_id, initiated_by
        ))
        return cursor.lastrowid


def get_transaction(txn_id: int, db_path: Optional[Path] = None) -> Optional[Dict[str, Any]]:
    """Get transaction by ID."""
    with get_connection(db_path) as conn:
        cursor = conn.cursor()
        cursor.execute("SELECT * FROM transactions WHERE id = ?", (txn_id,))
        row = cursor.fetchone()
        return dict(row) if row else None


def get_user_transactions(
    user_id: int,
    limit: int = 20,
    offset: int = 0,
    db_path: Optional[Path] = None
) -> List[Dict[str, Any]]:
    """Get transactions for a user."""
    with get_connection(db_path) as conn:
        cursor = conn.cursor()
        cursor.execute("""
            SELECT * FROM transactions
            WHERE user_id = ?
            ORDER BY id DESC
            LIMIT ? OFFSET ?
        """, (user_id, limit, offset))
        return [dict(row) for row in cursor.fetchall()]


def get_user_generations(
    user_id: int,
    limit: int = 10,
    offset: int = 0,
    db_path: Optional[Path] = None
) -> List[Dict[str, Any]]:
    """
    Get generation transactions for a user with video availability info.

    Returns list of generations with 'has_video' field indicating if video exists.
    """
    with get_connection(db_path) as conn:
        cursor = conn.cursor()
        cursor.execute("""
            SELECT * FROM transactions
            WHERE user_id = ? AND type IN ('generation', 'gift')
            ORDER BY id DESC
            LIMIT ? OFFSET ?
        """, (user_id, limit, offset))
        generations = [dict(row) for row in cursor.fetchall()]

    # Check video existence for each generation
    for gen in generations:
        task_id = gen.get("task_id")
        product_id = gen.get("product_id")
        gen["has_video"] = False
        gen["video_path"] = None

        if task_id and product_id:
            for prefix in ("wb", "avito", "ozon"):
                video_path = NFS_BASE / f"{prefix}_{product_id}" / task_id / "videos" / "video.mp4"
                if video_path.exists():
                    gen["has_video"] = True
                    gen["video_path"] = str(video_path)
                    break

    return generations


def get_user_generations_count(user_id: int, db_path: Optional[Path] = None) -> int:
    """Get total count of generations for a user."""
    with get_connection(db_path) as conn:
        cursor = conn.cursor()
        cursor.execute(
            "SELECT COUNT(*) as count FROM transactions WHERE user_id = ? AND type IN ('generation', 'gift')",
            (user_id,)
        )
        return cursor.fetchone()["count"]


def get_recent_transactions(
    limit: int = 50,
    txn_type: Optional[str] = None,
    db_path: Optional[Path] = None,
    offset: int = 0
) -> List[Dict[str, Any]]:
    """Get recent transactions across all users."""
    with get_connection(db_path) as conn:
        cursor = conn.cursor()

        if txn_type:
            cursor.execute("""
                SELECT t.*, u.username, u.first_name, u.last_name
                FROM transactions t
                LEFT JOIN users u ON t.user_id = u.user_id
                WHERE t.type = ?
                ORDER BY t.id DESC
                LIMIT ? OFFSET ?
            """, (txn_type, limit, offset))
        else:
            cursor.execute("""
                SELECT t.*, u.username, u.first_name, u.last_name
                FROM transactions t
                LEFT JOIN users u ON t.user_id = u.user_id
                ORDER BY t.id DESC
                LIMIT ? OFFSET ?
            """, (limit, offset))

        return [dict(row) for row in cursor.fetchall()]


def count_transactions(txn_type: Optional[str] = None, db_path: Optional[Path] = None) -> int:
    """Count total transactions."""
    with get_connection(db_path) as conn:
        cursor = conn.cursor()
        if txn_type:
            cursor.execute("SELECT COUNT(*) FROM transactions WHERE type = ?", (txn_type,))
        else:
            cursor.execute("SELECT COUNT(*) FROM transactions")
        return cursor.fetchone()[0]


def get_transaction_by_task(
    task_id: str,
    db_path: Optional[Path] = None
) -> Optional[Dict[str, Any]]:
    """Get transaction by task_id (for refunds)."""
    with get_connection(db_path) as conn:
        cursor = conn.cursor()
        cursor.execute(
            "SELECT * FROM transactions WHERE task_id = ? ORDER BY id DESC LIMIT 1",
            (task_id,)
        )
        row = cursor.fetchone()
        return dict(row) if row else None


# =============================================================================
# Promo Operations
# =============================================================================

def get_promo_remaining(db_path: Optional[Path] = None) -> int:
    """Get remaining promo slots."""
    with get_connection(db_path) as conn:
        cursor = conn.cursor()
        cursor.execute(
            "SELECT value FROM promo_config WHERE key = 'promo_users_remaining'"
        )
        row = cursor.fetchone()
        return int(row["value"]) if row else 0


def set_promo_remaining(count: int, db_path: Optional[Path] = None) -> None:
    """Set remaining promo slots."""
    with get_connection(db_path) as conn:
        cursor = conn.cursor()
        cursor.execute("""
            INSERT OR REPLACE INTO promo_config (key, value)
            VALUES ('promo_users_remaining', ?)
        """, (str(count),))


def set_user_promo_eligible(
    user_id: int,
    eligible: bool = True,
    db_path: Optional[Path] = None
) -> bool:
    """Set user's promo eligibility."""
    return update_user(user_id, {"is_promo_eligible": 1 if eligible else 0}, db_path)


# =============================================================================
# Giveaway Operations
# =============================================================================

def get_giveaway_config(db_path: Optional[Path] = None) -> Dict[str, str]:
    """Get all giveaway configuration values."""
    with get_connection(db_path) as conn:
        cursor = conn.cursor()
        cursor.execute("SELECT key, value FROM giveaway_config")
        return {row["key"]: row["value"] for row in cursor.fetchall()}


def is_giveaway_active(db_path: Optional[Path] = None) -> bool:
    """Check if giveaway is currently active."""
    with get_connection(db_path) as conn:
        cursor = conn.cursor()
        cursor.execute(
            "SELECT value FROM giveaway_config WHERE key = 'active'"
        )
        row = cursor.fetchone()
        return row["value"] == "1" if row else False


def get_giveaway_remaining(db_path: Optional[Path] = None) -> int:
    """Get remaining giveaway slots."""
    with get_connection(db_path) as conn:
        cursor = conn.cursor()
        cursor.execute(
            "SELECT value FROM giveaway_config WHERE key = 'remaining_users'"
        )
        row = cursor.fetchone()
        return int(row["value"]) if row else 0


def start_giveaway(
    tokens: int,
    users: int,
    admin_id: int,
    db_path: Optional[Path] = None
) -> None:
    """
    Start a new giveaway campaign.

    Args:
        tokens: Number of tokens per user
        users: Total number of users who can receive tokens
        admin_id: Admin user ID who started the campaign
    """
    with get_connection(db_path) as conn:
        cursor = conn.cursor()

        # Update config values individually to ensure proper updates
        cursor.execute("INSERT OR REPLACE INTO giveaway_config (key, value) VALUES ('active', '1')")
        cursor.execute("INSERT OR REPLACE INTO giveaway_config (key, value) VALUES ('tokens_per_user', ?)", (str(tokens),))
        cursor.execute("INSERT OR REPLACE INTO giveaway_config (key, value) VALUES ('remaining_users', ?)", (str(users),))
        cursor.execute("INSERT OR REPLACE INTO giveaway_config (key, value) VALUES ('started_at', datetime('now'))")
        cursor.execute("INSERT OR REPLACE INTO giveaway_config (key, value) VALUES ('started_by', ?)", (str(admin_id),))


def stop_giveaway(db_path: Optional[Path] = None) -> Dict[str, Any]:
    """
    Stop the active giveaway campaign.

    Returns:
        Dict with campaign statistics (tokens_granted, users_granted)
    """
    with get_connection(db_path) as conn:
        cursor = conn.cursor()

        # Get current config before stopping
        config = get_giveaway_config(db_path)
        initial_users = 0
        remaining_users = int(config.get("remaining_users", 0))

        # Calculate how many users received tokens
        # We need to check transactions to be accurate
        cursor.execute("""
            SELECT COUNT(*) as count, SUM(amount) as total
            FROM transactions
            WHERE type = 'giveaway'
              AND created_at >= (
                  SELECT value FROM giveaway_config WHERE key = 'started_at'
              )
        """)
        row = cursor.fetchone()
        users_granted = row["count"] if row else 0
        tokens_granted = row["total"] if row and row["total"] else 0

        # Set active to 0
        cursor.execute("""
            UPDATE giveaway_config SET value = '0' WHERE key = 'active'
        """)

        return {
            "users_granted": users_granted,
            "tokens_granted": tokens_granted,
            "remaining_users": remaining_users
        }


# =============================================================================
# Gift Pack Operations
# =============================================================================

def create_gift_pack(
    user_id: int,
    tokens: int,
    expiration_days: int = 7,
    campaign_id: Optional[str] = None,
    description: Optional[str] = None,
    created_by: Optional[int] = None,
    db_path: Optional[Path] = None
) -> int:
    """
    Create a gift pack for a user.

    Returns:
        Pack ID.
    """
    with get_connection(db_path) as conn:
        cursor = conn.cursor()
        cursor.execute("""
            INSERT INTO gift_packs (user_id, tokens, expires_at, campaign_id, description, created_by)
            VALUES (?, ?, datetime('now', '+' || ? || ' days'), ?, ?, ?)
        """, (user_id, tokens, expiration_days, campaign_id, description, created_by))
        return cursor.lastrowid


def get_user_active_packs(user_id: int, db_path: Optional[Path] = None) -> List[Dict[str, Any]]:
    """Get active non-expired packs for user, ordered by expiration (FIFO)."""
    with get_connection(db_path) as conn:
        cursor = conn.cursor()
        cursor.execute("""
            SELECT * FROM gift_packs
            WHERE user_id = ? AND status = 'active' AND expires_at > datetime('now')
            ORDER BY expires_at ASC
        """, (user_id,))
        return [dict(row) for row in cursor.fetchall()]


def redeem_gift_pack(pack_id: int, db_path: Optional[Path] = None) -> bool:
    """Set pack status to redeemed."""
    with get_connection(db_path) as conn:
        cursor = conn.cursor()
        cursor.execute("""
            UPDATE gift_packs
            SET status = 'redeemed', redeemed_at = CURRENT_TIMESTAMP
            WHERE id = ? AND status = 'active'
        """, (pack_id,))
        return cursor.rowcount > 0


def expire_gift_packs(db_path: Optional[Path] = None) -> int:
    """Bulk-expire overdue active packs. Returns count expired."""
    with get_connection(db_path) as conn:
        cursor = conn.cursor()
        cursor.execute("""
            UPDATE gift_packs
            SET status = 'expired', expired_at = CURRENT_TIMESTAMP
            WHERE status = 'active' AND expires_at <= datetime('now')
        """)
        return cursor.rowcount


def get_expiring_packs(hours_ahead: int = 24, db_path: Optional[Path] = None) -> List[Dict[str, Any]]:
    """Get packs expiring soon that haven't been notified."""
    with get_connection(db_path) as conn:
        cursor = conn.cursor()
        cursor.execute("""
            SELECT * FROM gift_packs
            WHERE status = 'active'
              AND expires_at <= datetime('now', '+' || ? || ' hours')
              AND expires_at > datetime('now')
              AND notified_at IS NULL
            ORDER BY expires_at ASC
        """, (hours_ahead,))
        return [dict(row) for row in cursor.fetchall()]


def mark_pack_notified(pack_id: int, db_path: Optional[Path] = None) -> None:
    """Set notified_at timestamp on a pack."""
    with get_connection(db_path) as conn:
        cursor = conn.cursor()
        cursor.execute("""
            UPDATE gift_packs SET notified_at = CURRENT_TIMESTAMP WHERE id = ?
        """, (pack_id,))


def get_user_packs(user_id: int, limit: int = 20, db_path: Optional[Path] = None) -> List[Dict[str, Any]]:
    """Get all packs for user (any status), newest first."""
    with get_connection(db_path) as conn:
        cursor = conn.cursor()
        cursor.execute("""
            SELECT * FROM gift_packs
            WHERE user_id = ?
            ORDER BY created_at DESC
            LIMIT ?
        """, (user_id, limit))
        return [dict(row) for row in cursor.fetchall()]


def get_gift_pack_stats(db_path: Optional[Path] = None) -> Dict[str, Any]:
    """Aggregate stats by status and campaign."""
    with get_connection(db_path) as conn:
        cursor = conn.cursor()

        # By status
        cursor.execute("""
            SELECT status, COUNT(*) as count, SUM(tokens) as total_tokens
            FROM gift_packs
            GROUP BY status
        """)
        by_status = {row["status"]: {"count": row["count"], "tokens": row["total_tokens"] or 0}
                     for row in cursor.fetchall()}

        # By campaign
        cursor.execute("""
            SELECT campaign_id, status, COUNT(*) as count, SUM(tokens) as total_tokens
            FROM gift_packs
            WHERE campaign_id IS NOT NULL
            GROUP BY campaign_id, status
        """)
        by_campaign = {}
        for row in cursor.fetchall():
            cid = row["campaign_id"]
            if cid not in by_campaign:
                by_campaign[cid] = {}
            by_campaign[cid][row["status"]] = {
                "count": row["count"],
                "tokens": row["total_tokens"] or 0
            }

        return {
            "by_status": by_status,
            "by_campaign": by_campaign,
            "total": sum(s["count"] for s in by_status.values()),
        }


def has_received_gift_pack(user_id: int, db_path: Optional[Path] = None) -> bool:
    """Check if user has already received a gift pack."""
    with get_connection(db_path) as conn:
        cursor = conn.cursor()
        cursor.execute(
            "SELECT gift_pack_received FROM users WHERE user_id = ?",
            (user_id,)
        )
        row = cursor.fetchone()
        return bool(row and row["gift_pack_received"])


def set_gift_pack_received(user_id: int, db_path: Optional[Path] = None) -> None:
    """Set gift_pack_received = 1 on user."""
    with get_connection(db_path) as conn:
        cursor = conn.cursor()
        cursor.execute(
            "UPDATE users SET gift_pack_received = 1, updated_at = CURRENT_TIMESTAMP WHERE user_id = ?",
            (user_id,)
        )


# =============================================================================
# Gift Pack Campaign Operations
# =============================================================================

def create_gift_pack_campaign(
    campaign_type: str,
    tokens: int = 3,
    expiration_days: int = 7,
    ref_source: Optional[str] = None,
    remaining_slots: int = -1,
    description: Optional[str] = None,
    created_by: Optional[int] = None,
    db_path: Optional[Path] = None
) -> int:
    """Create a gift pack campaign rule. Returns campaign ID."""
    with get_connection(db_path) as conn:
        cursor = conn.cursor()
        cursor.execute("""
            INSERT INTO gift_pack_campaigns
                (campaign_type, ref_source, tokens, expiration_days, remaining_slots, description, created_by)
            VALUES (?, ?, ?, ?, ?, ?, ?)
        """, (campaign_type, ref_source, tokens, expiration_days, remaining_slots, description, created_by))
        return cursor.lastrowid


def get_active_campaigns(db_path: Optional[Path] = None) -> List[Dict[str, Any]]:
    """Get all active campaigns."""
    with get_connection(db_path) as conn:
        cursor = conn.cursor()
        cursor.execute("""
            SELECT * FROM gift_pack_campaigns WHERE is_active = 1
        """)
        return [dict(row) for row in cursor.fetchall()]


def get_matching_campaign(
    is_new_user: bool,
    ref_source: Optional[str] = None,
    db_path: Optional[Path] = None
) -> Optional[Dict[str, Any]]:
    """
    Find best matching campaign: deeplink match first, then new_user.

    Returns:
        Campaign dict or None.
    """
    with get_connection(db_path) as conn:
        cursor = conn.cursor()

        # Priority 1: deeplink campaign matching user's ref_source
        if ref_source:
            cursor.execute("""
                SELECT * FROM gift_pack_campaigns
                WHERE is_active = 1
                  AND campaign_type = 'deeplink'
                  AND ref_source = ?
                  AND (remaining_slots > 0 OR remaining_slots = -1)
                ORDER BY id DESC LIMIT 1
            """, (ref_source,))
            row = cursor.fetchone()
            if row:
                return dict(row)

        # Priority 2: new_user campaign
        if is_new_user:
            cursor.execute("""
                SELECT * FROM gift_pack_campaigns
                WHERE is_active = 1
                  AND campaign_type = 'new_user'
                  AND (remaining_slots > 0 OR remaining_slots = -1)
                ORDER BY id DESC LIMIT 1
            """)
            row = cursor.fetchone()
            if row:
                return dict(row)

        return None


def deactivate_campaign(campaign_id: int, db_path: Optional[Path] = None) -> bool:
    """Deactivate a campaign."""
    with get_connection(db_path) as conn:
        cursor = conn.cursor()
        cursor.execute(
            "UPDATE gift_pack_campaigns SET is_active = 0 WHERE id = ?",
            (campaign_id,)
        )
        return cursor.rowcount > 0


def decrement_campaign_slots(campaign_id: int, db_path: Optional[Path] = None) -> None:
    """Decrement remaining_slots (if > 0). Does not decrement unlimited (-1)."""
    with get_connection(db_path) as conn:
        cursor = conn.cursor()
        cursor.execute("""
            UPDATE gift_pack_campaigns
            SET remaining_slots = remaining_slots - 1
            WHERE id = ? AND remaining_slots > 0
        """, (campaign_id,))


def get_all_campaigns(include_inactive: bool = False, db_path: Optional[Path] = None) -> List[Dict[str, Any]]:
    """List campaigns for admin."""
    with get_connection(db_path) as conn:
        cursor = conn.cursor()
        if include_inactive:
            cursor.execute("SELECT * FROM gift_pack_campaigns ORDER BY created_at DESC")
        else:
            cursor.execute("SELECT * FROM gift_pack_campaigns WHERE is_active = 1 ORDER BY created_at DESC")
        return [dict(row) for row in cursor.fetchall()]


def get_inactive_users(db_path: Optional[Path] = None) -> List[Dict[str, Any]]:
    """Get users who never purchased or spent tokens and never received a gift pack."""
    with get_connection(db_path) as conn:
        cursor = conn.cursor()
        cursor.execute("""
            SELECT * FROM users
            WHERE total_purchased = 0
              AND total_spent = 0
              AND gift_pack_received = 0
            ORDER BY created_at DESC
        """)
        return [dict(row) for row in cursor.fetchall()]


# =============================================================================
# Stale Generation Recovery
# =============================================================================

def find_stale_generations(
    since_hours: int = 24,
    db_path: Optional[Path] = None
) -> List[Dict[str, Any]]:
    """
    Find generation transactions that didn't complete (no video file, no refund).

    This is used to recover from bot restarts during generation.
    A generation is considered stale if:
    1. It's a 'generation' transaction from the last N hours
    2. There's no 'refund' transaction with the same task_id
    3. The video file doesn't exist

    Args:
        since_hours: Look back this many hours for generations.
        db_path: Optional database path.

    Returns:
        List of stale generation transactions with user_id, task_id, etc.
    """
    with get_connection(db_path) as conn:
        cursor = conn.cursor()

        # Find generation transactions without corresponding refunds
        cursor.execute("""
            SELECT g.*
            FROM transactions g
            WHERE g.type = 'generation'
              AND g.created_at > datetime('now', ?)
              AND NOT EXISTS (
                  SELECT 1 FROM transactions r
                  WHERE r.type = 'refund'
                    AND r.task_id = g.task_id
              )
            ORDER BY g.created_at DESC
        """, (f'-{since_hours} hours',))

        generations = [dict(row) for row in cursor.fetchall()]

    # Filter to only those where video doesn't exist
    stale = []
    for gen in generations:
        task_id = gen.get("task_id")
        product_id = gen.get("product_id")

        if not task_id:
            continue

        # Check if video exists
        # Path pattern: /mnt/video/{prefix}_{product_id}/{task_id}/videos/video.mp4
        if product_id:
            video_found = False
            for prefix in ("wb", "avito", "ozon"):
                video_path = NFS_BASE / f"{prefix}_{product_id}" / task_id / "videos" / "video.mp4"
                if video_path.exists():
                    video_found = True
                    break
            if video_found:
                continue  # Video exists, generation completed
        else:
            # No product_id, try to find by task_id pattern
            import glob
            pattern = str(NFS_BASE / "*_*" / task_id / "videos" / "video.mp4")
            if glob.glob(pattern):
                continue  # Video exists

        stale.append(gen)

    return stale


def find_undelivered_generations(
    since_hours: int = 24,
    db_path: Optional[Path] = None
) -> List[Dict[str, Any]]:
    """
    Find generation transactions where the video was created but never delivered.

    A generation is considered undelivered if:
    1. It's a 'generation' transaction from the last N hours
    2. There's no 'refund' transaction with the same task_id
    3. The video file exists
    4. The .delivered marker file does NOT exist
    """
    with get_connection(db_path) as conn:
        cursor = conn.cursor()

        cursor.execute("""
            SELECT g.*
            FROM transactions g
            WHERE g.type = 'generation'
              AND g.created_at > datetime('now', ?)
              AND NOT EXISTS (
                  SELECT 1 FROM transactions r
                  WHERE r.type = 'refund'
                    AND r.task_id = g.task_id
              )
            ORDER BY g.created_at DESC
        """, (f'-{since_hours} hours',))

        generations = [dict(row) for row in cursor.fetchall()]

    undelivered = []
    for gen in generations:
        task_id = gen.get("task_id")
        product_id = gen.get("product_id")

        if not task_id or not product_id:
            continue

        # Check if video exists but was not delivered
        for prefix in ("wb", "avito"):
            task_dir = NFS_BASE / f"{prefix}_{product_id}" / task_id
            video_path = task_dir / "videos" / "video.mp4"
            delivered_marker = task_dir / ".delivered"

            if video_path.exists() and not delivered_marker.exists():
                gen["video_path"] = str(video_path)
                gen["task_dir"] = str(task_dir)
                undelivered.append(gen)
                break

    return undelivered


# =============================================================================
# Statistics
# =============================================================================

def get_stats(db_path: Optional[Path] = None) -> Dict[str, Any]:
    """Get overall statistics."""
    with get_connection(db_path) as conn:
        cursor = conn.cursor()

        # User stats
        cursor.execute("SELECT COUNT(*) as count FROM users")
        total_users = cursor.fetchone()["count"]

        cursor.execute("SELECT COUNT(*) as count FROM users WHERE balance > 0")
        users_with_balance = cursor.fetchone()["count"]

        cursor.execute("SELECT COUNT(*) as count FROM users WHERE is_blocked = 1")
        blocked_users = cursor.fetchone()["count"]

        cursor.execute("SELECT SUM(balance) as total FROM users")
        total_balance = cursor.fetchone()["total"] or 0

        # Transaction stats
        cursor.execute("""
            SELECT type, COUNT(*) as count, SUM(ABS(amount)) as total_amount
            FROM transactions
            GROUP BY type
        """)
        txn_stats = {row["type"]: {"count": row["count"], "total": row["total_amount"]}
                     for row in cursor.fetchall()}

        # Revenue
        cursor.execute("""
            SELECT SUM(amount_rub) as total
            FROM transactions
            WHERE type = 'purchase' AND amount_rub IS NOT NULL
        """)
        total_revenue = cursor.fetchone()["total"] or 0

        # Promo stats
        cursor.execute("SELECT COUNT(*) as count FROM users WHERE is_promo_eligible = 1")
        promo_users = cursor.fetchone()["count"]

        promo_remaining = get_promo_remaining(db_path)

        return {
            "total_users": total_users,
            "users_with_balance": users_with_balance,
            "blocked_users": blocked_users,
            "total_balance": total_balance,
            "transactions": txn_stats,
            "total_revenue_kopecks": total_revenue,
            "total_revenue_rub": total_revenue / 100 if total_revenue else 0,
            "promo_users": promo_users,
            "promo_remaining": promo_remaining,
        }


def get_ref_stats(db_path: Optional[Path] = None) -> List[Dict[str, Any]]:
    """
    Get aggregate referral source statistics.

    Returns:
        List of dicts with 'ref_source' and 'count', ordered by count DESC.
        Includes a row with ref_source=None for users without a source.
    """
    with get_connection(db_path) as conn:
        cursor = conn.cursor()
        cursor.execute("""
            SELECT ref_source, COUNT(*) as count
            FROM users
            GROUP BY ref_source
            ORDER BY count DESC
        """)
        return [dict(row) for row in cursor.fetchall()]


# =============================================================================
# Showcase Videos (shared database for portfolio examples)
# =============================================================================

def init_showcase_db() -> None:
    """
    Initialize showcase database schema.

    Creates showcase_videos table if it doesn't exist.
    This is a separate shared database used by both dev and prod.
    """
    SHOWCASE_DB_PATH.parent.mkdir(parents=True, exist_ok=True)

    conn = sqlite3.connect(str(SHOWCASE_DB_PATH))
    conn.row_factory = sqlite3.Row
    cursor = conn.cursor()

    cursor.execute("""
        CREATE TABLE IF NOT EXISTS showcase_videos (
            id INTEGER PRIMARY KEY AUTOINCREMENT,
            video_path TEXT NOT NULL UNIQUE,
            task_id TEXT,
            product_id TEXT,
            rating INTEGER DEFAULT 0,
            has_artifacts INTEGER DEFAULT 0,
            is_active INTEGER DEFAULT 1,
            added_by INTEGER,
            added_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
        )
    """)

    cursor.execute("""
        CREATE INDEX IF NOT EXISTS idx_showcase_videos_active
        ON showcase_videos(is_active)
    """)

    cursor.execute("""
        CREATE INDEX IF NOT EXISTS idx_showcase_videos_task_id
        ON showcase_videos(task_id)
    """)

    conn.commit()
    conn.close()


@contextmanager
def get_showcase_connection():
    """Context manager for showcase database connections."""
    conn = sqlite3.connect(str(SHOWCASE_DB_PATH))
    conn.row_factory = sqlite3.Row
    try:
        yield conn
        conn.commit()
    except Exception:
        conn.rollback()
        raise
    finally:
        conn.close()


def add_showcase_video(
    video_path: str,
    task_id: Optional[str] = None,
    product_id: Optional[str] = None,
    rating: int = 0,
    has_artifacts: bool = False,
    added_by: Optional[int] = None
) -> Optional[int]:
    """
    Add a video to the showcase.

    Returns:
        ID of the new showcase entry, or None if already exists.
    """
    with get_showcase_connection() as conn:
        cursor = conn.cursor()
        try:
            cursor.execute("""
                INSERT INTO showcase_videos
                (video_path, task_id, product_id, rating, has_artifacts, added_by)
                VALUES (?, ?, ?, ?, ?, ?)
            """, (video_path, task_id, product_id, rating, 1 if has_artifacts else 0, added_by))
            return cursor.lastrowid
        except sqlite3.IntegrityError:
            # Already exists
            return None


def remove_showcase_video(video_id: int) -> bool:
    """
    Remove a video from the showcase by ID.

    Returns:
        True if video was removed.
    """
    with get_showcase_connection() as conn:
        cursor = conn.cursor()
        cursor.execute("DELETE FROM showcase_videos WHERE id = ?", (video_id,))
        return cursor.rowcount > 0


def get_showcase_video(video_id: int) -> Optional[Dict[str, Any]]:
    """Get a showcase video by ID."""
    with get_showcase_connection() as conn:
        cursor = conn.cursor()
        cursor.execute("SELECT * FROM showcase_videos WHERE id = ?", (video_id,))
        row = cursor.fetchone()
        return dict(row) if row else None


def get_showcase_video_by_task(task_id: str) -> Optional[Dict[str, Any]]:
    """Get a showcase video by task_id."""
    with get_showcase_connection() as conn:
        cursor = conn.cursor()
        cursor.execute("SELECT * FROM showcase_videos WHERE task_id = ?", (task_id,))
        row = cursor.fetchone()
        return dict(row) if row else None


def get_showcase_videos(
    active_only: bool = True,
    exclude_artifacts: bool = True,
    limit: Optional[int] = None,
    offset: int = 0
) -> List[Dict[str, Any]]:
    """
    Get showcase videos with optional filters.

    Args:
        active_only: Only return active videos.
        exclude_artifacts: Exclude videos marked as having artifacts.
        limit: Maximum number of videos to return.
        offset: Number of videos to skip.

    Returns:
        List of showcase video dicts.
    """
    with get_showcase_connection() as conn:
        cursor = conn.cursor()

        conditions = []
        params = []

        if active_only:
            conditions.append("is_active = 1")
        if exclude_artifacts:
            conditions.append("has_artifacts = 0")

        where_clause = f"WHERE {' AND '.join(conditions)}" if conditions else ""
        limit_clause = f"LIMIT {limit}" if limit else ""
        offset_clause = f"OFFSET {offset}" if offset else ""

        query = f"""
            SELECT * FROM showcase_videos
            {where_clause}
            ORDER BY rating DESC, added_at DESC
            {limit_clause} {offset_clause}
        """

        cursor.execute(query)
        return [dict(row) for row in cursor.fetchall()]


def get_showcase_videos_count(
    active_only: bool = True,
    exclude_artifacts: bool = True
) -> int:
    """Get total count of showcase videos matching filters."""
    with get_showcase_connection() as conn:
        cursor = conn.cursor()

        conditions = []

        if active_only:
            conditions.append("is_active = 1")
        if exclude_artifacts:
            conditions.append("has_artifacts = 0")

        where_clause = f"WHERE {' AND '.join(conditions)}" if conditions else ""

        cursor.execute(f"SELECT COUNT(*) as count FROM showcase_videos {where_clause}")
        return cursor.fetchone()["count"]


def get_random_showcase_videos(
    count: int = 5,
    exclude_artifacts: bool = True
) -> List[Dict[str, Any]]:
    """
    Get random showcase videos for portfolio display.

    Args:
        count: Number of videos to return.
        exclude_artifacts: Exclude videos marked as having artifacts.

    Returns:
        List of random showcase video dicts.
    """
    with get_showcase_connection() as conn:
        cursor = conn.cursor()

        conditions = ["is_active = 1"]
        if exclude_artifacts:
            conditions.append("has_artifacts = 0")

        where_clause = f"WHERE {' AND '.join(conditions)}"

        cursor.execute(f"""
            SELECT * FROM showcase_videos
            {where_clause}
            ORDER BY RANDOM()
            LIMIT ?
        """, (count,))

        return [dict(row) for row in cursor.fetchall()]


def set_showcase_video_active(video_id: int, active: bool) -> bool:
    """
    Set a showcase video's active status.

    Returns:
        True if video was updated.
    """
    with get_showcase_connection() as conn:
        cursor = conn.cursor()
        cursor.execute(
            "UPDATE showcase_videos SET is_active = ? WHERE id = ?",
            (1 if active else 0, video_id)
        )
        return cursor.rowcount > 0


def set_showcase_video_artifacts(video_id: int, has_artifacts: bool) -> bool:
    """
    Set a showcase video's artifacts flag.

    Returns:
        True if video was updated.
    """
    with get_showcase_connection() as conn:
        cursor = conn.cursor()
        cursor.execute(
            "UPDATE showcase_videos SET has_artifacts = ? WHERE id = ?",
            (1 if has_artifacts else 0, video_id)
        )
        return cursor.rowcount > 0


def set_showcase_video_rating(video_id: int, rating: int) -> bool:
    """
    Set a showcase video's rating (1-5).

    Returns:
        True if video was updated.
    """
    rating = max(0, min(5, rating))  # Clamp to 0-5
    with get_showcase_connection() as conn:
        cursor = conn.cursor()
        cursor.execute(
            "UPDATE showcase_videos SET rating = ? WHERE id = ?",
            (rating, video_id)
        )
        return cursor.rowcount > 0


# =============================================================================
# CLI
# =============================================================================

if __name__ == "__main__":
    import sys

    if len(sys.argv) < 2:
        print("Usage:")
        print("  python database.py init [dev|prod]  - Initialize database")
        print("  python database.py stats [dev|prod] - Show statistics")
        print("  python database.py showcase init    - Initialize showcase database")
        print("  python database.py showcase stats   - Show showcase statistics")
        sys.exit(1)

    cmd = sys.argv[1]

    if cmd == "showcase":
        subcmd = sys.argv[2] if len(sys.argv) > 2 else "init"

        if subcmd == "init":
            init_showcase_db()
            print(f"Showcase database initialized: {SHOWCASE_DB_PATH}")

        elif subcmd == "stats":
            init_showcase_db()
            total = get_showcase_videos_count(active_only=False, exclude_artifacts=False)
            active = get_showcase_videos_count(active_only=True, exclude_artifacts=False)
            clean = get_showcase_videos_count(active_only=True, exclude_artifacts=True)
            print(f"\n📊 Showcase Statistics:")
            print(f"  Total videos: {total}")
            print(f"  Active: {active}")
            print(f"  Clean (no artifacts): {clean}")

        else:
            print(f"Unknown showcase command: {subcmd}")
            sys.exit(1)

    else:
        source = sys.argv[2] if len(sys.argv) > 2 else "dev"
        db_path = get_db_path(source)

        if cmd == "init":
            init_db(db_path)

        elif cmd == "stats":
            init_db(db_path)  # Ensure tables exist
            stats = get_stats(db_path)
            print(f"\n📊 Statistics for {source}:")
            print(f"  Users: {stats['total_users']} total, {stats['users_with_balance']} with balance")
            print(f"  Blocked: {stats['blocked_users']}")
            print(f"  Total balance: {stats['total_balance']} tokens")
            print(f"  Revenue: {stats['total_revenue_rub']:.2f} RUB")
            print(f"  Promo: {stats['promo_users']} eligible, {stats['promo_remaining']} slots remaining")
            print(f"\n  Transactions:")
            for txn_type, data in stats.get("transactions", {}).items():
                print(f"    {txn_type}: {data['count']} ({data['total']} tokens)")

        else:
            print(f"Unknown command: {cmd}")
            sys.exit(1)
