import logging
import random

import psycopg2.extras

import config
from db import get_conn
from .economy import economy

logger = logging.getLogger(__name__)

SLOT_SYMBOLS = ["🍒", "🍋", "🔔", "💎", "7️⃣", "🍀"]
SLOT_WEIGHTS = [30, 25, 20, 12, 8, 5]

MULTIPLIERS = {
    2: (1.2, 1.8),
    3: (2.0, 3.0),
}

CASINO_WIN_CHANCE = 0.35


def spin_slots() -> tuple[list[str], int]:
    reels = random.choices(SLOT_SYMBOLS, weights=SLOT_WEIGHTS, k=3)

    if random.random() > CASINO_WIN_CHANCE:
        while len(set(reels)) < 3:
            reels = random.choices(SLOT_SYMBOLS, weights=SLOT_WEIGHTS, k=3)
        return reels, 0

    counts = {}
    for s in reels:
        counts[s] = counts.get(s, 0) + 1
    return reels, max(counts.values())


def get_user_length(user_id: int) -> float | None:
    try:
        with get_conn() as conn:
            cur = conn.cursor(cursor_factory=psycopg2.extras.RealDictCursor)
            cur.execute('SELECT balance FROM user_balances WHERE user_id = %s', (user_id,))
            row = cur.fetchone()
        return float(row['balance']) if row else None
    except Exception:
        logger.exception("casino: failed to get balance")
        return None


def update_user_length(user_id: int, delta: float) -> float | None:
    try:
        with get_conn() as conn:
            cur = conn.cursor(cursor_factory=psycopg2.extras.RealDictCursor)
            cur.execute('SELECT balance FROM user_balances WHERE user_id = %s', (user_id,))
            row = cur.fetchone()
            if row is None:
                return None
            new_balance = round(float(row['balance']) + delta, 1)
            if delta < 0 and new_balance < 0:
                new_balance = 0.0
            wcur = conn.cursor()
            wcur.execute(
                'UPDATE user_balances SET balance = %s WHERE user_id = %s',
                (new_balance, user_id),
            )
        return new_balance
    except Exception:
        logger.exception("casino: failed to update balance")
        return None


def play_casino(user_id: int, bet: float) -> str:
    current = economy.get_user_balance(user_id)

    if bet > config.CASINO_MAX_BET:
        return f"Максимальная ставка — {config.CASINO_MAX_BET} см, не жадничай."
    if bet <= 0:
        return "Ставка должна быть больше нуля, фраер."
    if round(bet, 2) > round(current, 2):
        return f"У тебя {current:.1f} см, а ставишь {bet:.1f}. Столько нет, фраер."

    reels, matches = spin_slots()
    slots_display = " | ".join(reels)

    if matches >= 2:
        min_mult, max_mult = MULTIPLIERS[matches]
        multiplier = round(random.uniform(min_mult, max_mult), 1)
        winnings = round(bet * multiplier, 1)
        economy.update_balance(user_id, winnings, 'casino_win', f'Выигрыш в казино x{multiplier}')
        new_balance = economy.get_user_balance(user_id)

        if matches == 3:
            return (
                f"🎰 {slots_display}\n\n"
                f"🎉 ДЖЕКПОТ!!! Три одинаковых!\n"
                f"Множитель: x{multiplier}\n"
                f"Выигрыш: +{winnings:.1f} см\n"
                f"💰 Баланс: {new_balance:.1f} см"
            )
        return (
            f"🎰 {slots_display}\n\n"
            f"✅ Выигрыш! Две совпали.\n"
            f"Множитель: x{multiplier}\n"
            f"Выигрыш: +{winnings:.1f} см\n"
            f"💰 Баланс: {new_balance:.1f} см"
        )
    else:
        economy.update_balance(user_id, -bet, 'casino_loss', f'Проигрыш в казино -{bet} см')
        new_balance = economy.get_user_balance(user_id)
        return (
            f"🎰 {slots_display}\n\n"
            f"❌ Мимо, братуха.\n"
            f"Проигрыш: -{bet:.1f} см\n"
            f"💰 Баланс: {new_balance:.1f} см"
        )
