import logging
import random
from datetime import datetime, timedelta
from typing import Dict

import psycopg2.extras

from db import get_conn

logger = logging.getLogger(__name__)


class EconomyManager:
    def __init__(self):
        self.init_db()

    def init_db(self):
        with get_conn() as conn:
            cur = conn.cursor()

            cur.execute('''
                CREATE TABLE IF NOT EXISTS user_balances (
                    user_id BIGINT PRIMARY KEY,
                    balance REAL DEFAULT 0.0,
                    daily_income REAL DEFAULT 0.0,
                    last_daily_reset DATE,
                    created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
                )
            ''')

            cur.execute('''
                CREATE TABLE IF NOT EXISTS deposits (
                    id SERIAL PRIMARY KEY,
                    user_id BIGINT,
                    amount REAL,
                    interest_rate REAL,
                    created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
                    matures_at TIMESTAMP,
                    is_active BOOLEAN DEFAULT TRUE
                )
            ''')

            cur.execute('''
                CREATE TABLE IF NOT EXISTS loans (
                    id SERIAL PRIMARY KEY,
                    user_id BIGINT,
                    amount REAL,
                    interest_rate REAL,
                    created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
                    due_at TIMESTAMP,
                    is_repaid BOOLEAN DEFAULT FALSE
                )
            ''')

            cur.execute('''
                CREATE TABLE IF NOT EXISTS transactions (
                    id SERIAL PRIMARY KEY,
                    from_user_id BIGINT,
                    to_user_id BIGINT,
                    amount REAL,
                    transaction_type TEXT,
                    description TEXT,
                    created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
                )
            ''')

            cur.execute('''
                CREATE TABLE IF NOT EXISTS taxes (
                    id SERIAL PRIMARY KEY,
                    user_id BIGINT,
                    amount REAL,
                    tax_date DATE,
                    created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
                )
            ''')

            cur.execute('''
                CREATE TABLE IF NOT EXISTS economy_settings (
                    key TEXT PRIMARY KEY,
                    value TEXT,
                    updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
                )
            ''')

            cur.execute('''
                CREATE TABLE IF NOT EXISTS daily_activity (
                    id SERIAL PRIMARY KEY,
                    user_id BIGINT,
                    activity_date DATE,
                    message_count INTEGER DEFAULT 0,
                    last_activity_time TIMESTAMP,
                    created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
                    UNIQUE (user_id, activity_date)
                )
            ''')

            cur.execute('''
                CREATE TABLE IF NOT EXISTS central_bank (
                    id INTEGER PRIMARY KEY DEFAULT 1,
                    capital REAL DEFAULT 1000.0,
                    total_taxes_collected REAL DEFAULT 0.0,
                    total_inflation_adjustments REAL DEFAULT 0.0,
                    total_emissions REAL DEFAULT 0.0,
                    last_updated TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
                    UNIQUE (id)
                )
            ''')

            cur.execute('''
                CREATE TABLE IF NOT EXISTS penis_stats (
                    user_id BIGINT PRIMARY KEY,
                    display_name TEXT NOT NULL DEFAULT '',
                    last_used_ts BIGINT
                )
            ''')

            default_settings = {
                'central_bank_rate': '7.5',
                'deposit_min_amount': '10.0',
                'deposit_min_days': '7',
                'loan_max_amount': '100.0',
                'loan_interest_rate': '15.0',
                'tax_rate': '13.0',
                'transfer_limit_percent': '20.0',
                'inflation_rate': '5.0',
                'vanomasa_cooldown': '30',
                'message_reward_rate': '0.01',
                'last_activity_payout': '',
            }

            for key, value in default_settings.items():
                cur.execute('''
                    INSERT INTO economy_settings (key, value) VALUES (%s, %s)
                    ON CONFLICT (key) DO NOTHING
                ''', (key, value))

            cur.execute('''
                INSERT INTO central_bank (id, capital) VALUES (1, 1000.0)
                ON CONFLICT (id) DO NOTHING
            ''')

    def get_user_balance(self, user_id: int) -> float:
        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,))
            result = cur.fetchone()
        return result['balance'] if result else 0.0

    def update_balance(self, user_id: int, amount: float, transaction_type: str, description: str = ""):
        with get_conn() as conn:
            cur = conn.cursor()
            cur.execute('''
                INSERT INTO user_balances (user_id, balance, daily_income, last_daily_reset)
                VALUES (%s, %s, 0.0, CURRENT_DATE)
                ON CONFLICT (user_id) DO UPDATE SET balance = user_balances.balance + %s
            ''', (user_id, amount, amount))

            cur.execute('''
                INSERT INTO transactions (from_user_id, to_user_id, amount, transaction_type, description)
                VALUES (%s, %s, %s, %s, %s)
            ''', (user_id, user_id, amount, transaction_type, description))

        logger.info(f"Balance updated for user {user_id}: +{amount} ({transaction_type})")

    def find_user_id_by_username(self, username: str) -> int | None:
        """Ищет user_id по @username в penis_stats (display_name хранится как '@username')."""
        name = username.lstrip('@').lower()
        with get_conn() as conn:
            cur = conn.cursor(cursor_factory=psycopg2.extras.RealDictCursor)
            cur.execute(
                "SELECT user_id FROM penis_stats WHERE LOWER(display_name) = %s OR LOWER(display_name) = %s",
                (f'@{name}', name),
            )
            row = cur.fetchone()
            return int(row['user_id']) if row else None

    def transfer_money(self, from_user_id: int, to_user_id: int, amount: float, description: str = "") -> bool:
        if amount <= 0:
            return False

        from_balance = self.get_user_balance(from_user_id)
        limit = round(from_balance * 0.2, 2)
        if round(amount, 2) > limit or round(from_balance, 2) < round(amount, 2):
            return False

        with get_conn() as conn:
            cur = conn.cursor()
            cur.execute(
                'UPDATE user_balances SET balance = balance - %s WHERE user_id = %s',
                (amount, from_user_id),
            )
            cur.execute('''
                INSERT INTO user_balances (user_id, balance, daily_income, last_daily_reset)
                VALUES (%s, %s, 0.0, CURRENT_DATE)
                ON CONFLICT (user_id) DO UPDATE SET balance = user_balances.balance + %s
            ''', (to_user_id, amount, amount))
            cur.execute('''
                INSERT INTO transactions (from_user_id, to_user_id, amount, transaction_type, description)
                VALUES (%s, %s, %s, 'transfer', %s)
            ''', (from_user_id, to_user_id, amount, description))

        logger.info(f"Transfer: {amount} from user {from_user_id} to user {to_user_id}")
        return True

    def create_deposit(self, user_id: int, amount: float, days: int) -> tuple[bool, str]:
        if amount <= 0:
            return False, "Сумма вклада должна быть больше нуля."

        balance = self.get_user_balance(user_id)
        min_deposit = float(self.get_setting('deposit_min_amount'))

        if round(amount, 2) < round(min_deposit, 2):
            return False, f"Минимальная сумма вклада — {min_deposit:.1f} см. Твой баланс: {balance:.1f} см."
        if round(balance, 2) < round(amount, 2):
            return False, f"Недостаточно средств. Твой баланс: {balance:.1f} см, а сумма вклада: {amount:.1f} см."

        central_bank_rate = float(self.get_setting('central_bank_rate'))
        matures_at = datetime.now() + timedelta(days=days)

        with get_conn() as conn:
            cur = conn.cursor()
            cur.execute(
                'UPDATE user_balances SET balance = balance - %s WHERE user_id = %s',
                (amount, user_id),
            )
            cur.execute('''
                UPDATE central_bank SET capital = capital + %s, last_updated = CURRENT_TIMESTAMP
                WHERE id = 1
            ''', (amount,))
            cur.execute('''
                INSERT INTO deposits (user_id, amount, interest_rate, matures_at)
                VALUES (%s, %s, %s, %s)
            ''', (user_id, amount, central_bank_rate, matures_at))

        logger.info(f"Deposit created: user {user_id}, amount {amount}, rate {central_bank_rate}%")
        return True, "Вклад успешно открыт!"

    def create_loan(self, user_id: int, amount: float, days: int) -> bool:
        if amount <= 0:
            return False

        max_loan = float(self.get_setting('loan_max_amount'))
        loan_rate = float(self.get_setting('loan_interest_rate'))

        if round(amount, 2) > round(max_loan, 2):
            return False

        with get_conn() as conn:
            cur = conn.cursor(cursor_factory=psycopg2.extras.RealDictCursor)

            # Лимит суммарного долга на юзера = max_loan
            cur.execute(
                "SELECT COALESCE(SUM(amount),0) AS total FROM loans WHERE user_id=%s AND is_repaid=FALSE",
                (user_id,),
            )
            outstanding = float(cur.fetchone()['total'])
            if round(outstanding + amount, 2) > round(max_loan, 2):
                return False

            # ЦБ должен иметь достаточно капитала
            cur.execute("SELECT capital FROM central_bank WHERE id=1")
            cb_capital = float(cur.fetchone()['capital'])
            if round(cb_capital, 2) < round(amount, 2):
                return False

        due_at = datetime.now() + timedelta(days=days)

        with get_conn() as conn:
            cur = conn.cursor()
            cur.execute('''
                UPDATE central_bank SET capital = capital - %s, last_updated = CURRENT_TIMESTAMP
                WHERE id = 1
            ''', (amount,))
            cur.execute('''
                INSERT INTO user_balances (user_id, balance, daily_income, last_daily_reset)
                VALUES (%s, %s, 0.0, CURRENT_DATE)
                ON CONFLICT (user_id) DO UPDATE SET balance = user_balances.balance + %s
            ''', (user_id, amount, amount))
            cur.execute('''
                INSERT INTO loans (user_id, amount, interest_rate, due_at)
                VALUES (%s, %s, %s, %s)
            ''', (user_id, amount, loan_rate, due_at))

        logger.info(f"Loan created: user {user_id}, amount {amount}, rate {loan_rate}%")
        return True

    def repay_loan(self, user_id: int, loan_id: int) -> bool:
        with get_conn() as conn:
            cur = conn.cursor(cursor_factory=psycopg2.extras.RealDictCursor)
            cur.execute(
                'SELECT amount, interest_rate, is_repaid FROM loans WHERE id = %s AND user_id = %s',
                (loan_id, user_id),
            )
            loan = cur.fetchone()

            if not loan or loan['is_repaid']:
                return False

            total_repayment = round(loan['amount'] * (1 + loan['interest_rate'] / 100), 2)

            balance = self.get_user_balance(user_id)
            if round(balance, 2) < total_repayment:
                return False

            wcur = conn.cursor()
            wcur.execute(
                'UPDATE user_balances SET balance = balance - %s WHERE user_id = %s',
                (total_repayment, user_id),
            )
            wcur.execute('''
                UPDATE central_bank SET capital = capital + %s, last_updated = CURRENT_TIMESTAMP
                WHERE id = 1
            ''', (total_repayment,))
            wcur.execute('UPDATE loans SET is_repaid = TRUE WHERE id = %s', (loan_id,))

        logger.info(f"Loan repaid: user {user_id}, loan {loan_id}, amount {total_repayment}")
        return True

    def collect_daily_taxes(self):
        tax_rate = float(self.get_setting('tax_rate')) / 100

        with get_conn() as conn:
            cur = conn.cursor(cursor_factory=psycopg2.extras.RealDictCursor)
            cur.execute('''
                SELECT user_id, daily_income FROM user_balances
                WHERE daily_income > 0 AND (last_daily_reset != CURRENT_DATE OR last_daily_reset IS NULL)
            ''')
            users = cur.fetchall()

            total_taxes_collected = 0.0
            wcur = conn.cursor()

            for row in users:
                user_id = row['user_id']
                daily_income = row['daily_income']
                tax_amount = daily_income * tax_rate
                if tax_amount <= 0:
                    continue

                wcur.execute('''
                    UPDATE user_balances
                    SET balance = balance - %s, daily_income = 0, last_daily_reset = CURRENT_DATE
                    WHERE user_id = %s
                ''', (tax_amount, user_id))
                wcur.execute(
                    'INSERT INTO taxes (user_id, amount, tax_date) VALUES (%s, %s, CURRENT_DATE)',
                    (user_id, tax_amount),
                )
                total_taxes_collected += tax_amount

            if total_taxes_collected > 0:
                wcur.execute('''
                    UPDATE central_bank
                    SET capital = capital + %s, total_taxes_collected = total_taxes_collected + %s
                    WHERE id = 1
                ''', (total_taxes_collected, total_taxes_collected))

        logger.info(f"Daily taxes collected: {total_taxes_collected:.2f} cm from {len(users)} users")

    def count_message(self, user_id: int):
        today = datetime.now().strftime('%Y-%m-%d')
        with get_conn() as conn:
            cur = conn.cursor()
            cur.execute('''
                INSERT INTO daily_activity (user_id, activity_date, message_count, last_activity_time)
                VALUES (%s, %s, 1, CURRENT_TIMESTAMP)
                ON CONFLICT (user_id, activity_date) DO UPDATE SET
                    message_count = daily_activity.message_count + 1,
                    last_activity_time = CURRENT_TIMESTAMP
            ''', (user_id, today))

    def pay_daily_activity_rewards(self) -> int:
        reward_rate = float(self.get_setting('message_reward_rate'))
        last_payout = self.get_setting('last_activity_payout')
        today = datetime.now().strftime('%Y-%m-%d')

        if last_payout == today:
            return 0

        yesterday = (datetime.now() - timedelta(days=1)).strftime('%Y-%m-%d')

        with get_conn() as conn:
            cur = conn.cursor(cursor_factory=psycopg2.extras.RealDictCursor)
            cur.execute('''
                SELECT user_id, message_count FROM daily_activity
                WHERE activity_date = %s AND message_count > 0
            ''', (yesterday,))
            users = cur.fetchall()

            total_paid = 0.0
            wcur = conn.cursor()

            # Проверяем что у ЦБ есть деньги на выплаты
            wcur = conn.cursor()
            wcur.execute("SELECT capital FROM central_bank WHERE id=1")
            cb_row = wcur.fetchone()
            cb_capital = float(cb_row[0]) if cb_row else 0.0

            for row in users:
                user_id = row['user_id']
                message_count = row['message_count']
                reward = message_count * reward_rate
                if reward <= 0:
                    continue
                if cb_capital < reward:
                    logger.warning("CB out of funds for activity rewards, stopping early")
                    break

                wcur.execute('''
                    INSERT INTO user_balances (user_id, balance, daily_income, last_daily_reset)
                    VALUES (%s, %s, 0.0, CURRENT_DATE)
                    ON CONFLICT (user_id) DO UPDATE SET
                        balance = user_balances.balance + %s,
                        daily_income = user_balances.daily_income + %s
                ''', (user_id, reward, reward, reward))
                wcur.execute('''
                    UPDATE central_bank SET capital = capital - %s, last_updated = CURRENT_TIMESTAMP
                    WHERE id = 1
                ''', (reward,))
                wcur.execute('''
                    INSERT INTO transactions (from_user_id, to_user_id, amount, transaction_type, description)
                    VALUES (0, %s, %s, 'activity_reward', %s)
                ''', (user_id, reward, f'Вознаграждение за {message_count} сообщений'))
                cb_capital -= reward
                total_paid += reward

            wcur.execute(
                'UPDATE economy_settings SET value = %s WHERE key = %s',
                (today, 'last_activity_payout'),
            )

        logger.info(f"Activity rewards paid: {total_paid:.2f} cm to {len(users)} users")
        return len(users)

    def get_central_bank_stats(self) -> Dict:
        with get_conn() as conn:
            cur = conn.cursor(cursor_factory=psycopg2.extras.RealDictCursor)
            cur.execute('''
                SELECT capital, total_taxes_collected, total_inflation_adjustments, total_emissions
                FROM central_bank WHERE id = 1
            ''')
            result = cur.fetchone()

        if result:
            return {
                'capital': result['capital'],
                'total_taxes_collected': result['total_taxes_collected'],
                'total_inflation_adjustments': result['total_inflation_adjustments'],
                'total_emissions': result['total_emissions'],
            }
        return {
            'capital': 1000.0,
            'total_taxes_collected': 0.0,
            'total_inflation_adjustments': 0.0,
            'total_emissions': 0.0,
        }

    def update_central_bank(self, capital_change: float, transaction_type: str, description: str = ""):
        with get_conn() as conn:
            cur = conn.cursor()
            cur.execute('''
                UPDATE central_bank SET capital = capital + %s, last_updated = CURRENT_TIMESTAMP
                WHERE id = 1
            ''', (capital_change,))

            if transaction_type == 'tax':
                cur.execute('''
                    UPDATE central_bank
                    SET total_taxes_collected = total_taxes_collected + %s WHERE id = 1
                ''', (abs(capital_change),))
            elif transaction_type == 'inflation':
                cur.execute('''
                    UPDATE central_bank
                    SET total_inflation_adjustments = total_inflation_adjustments + %s WHERE id = 1
                ''', (abs(capital_change),))
            elif transaction_type == 'emission':
                cur.execute('''
                    UPDATE central_bank
                    SET total_emissions = total_emissions + %s WHERE id = 1
                ''', (abs(capital_change),))

        logger.info(f"Central bank updated: {capital_change} ({transaction_type})")

    def emit_money(self, amount: float, reason: str = "") -> bool:
        if round(self.get_central_bank_stats()['capital'], 2) < round(amount, 2):
            return False
        self.update_central_bank(-amount, 'emission', reason)
        logger.info(f"Money emitted: {amount} cm ({reason})")
        return True

    def vanomasa(self) -> bool:
        with get_conn() as conn:
            cur = conn.cursor(cursor_factory=psycopg2.extras.RealDictCursor)
            cur.execute("SELECT value FROM economy_settings WHERE key = %s", ('last_vanomasa',))
            last_vanomasa = cur.fetchone()

            if last_vanomasa and last_vanomasa['value']:
                try:
                    last_date = datetime.strptime(last_vanomasa['value'], '%Y-%m-%d')
                    cooldown_days = int(self.get_setting('vanomasa_cooldown'))
                    if datetime.now() - last_date < timedelta(days=cooldown_days):
                        return False
                except ValueError:
                    pass

            today = datetime.now().strftime('%Y-%m-%d')
            wcur = conn.cursor()
            wcur.execute('UPDATE user_balances SET balance = 0, daily_income = 0')
            wcur.execute('''
                INSERT INTO economy_settings (key, value, updated_at) VALUES (%s, %s, CURRENT_TIMESTAMP)
                ON CONFLICT (key) DO UPDATE SET value = EXCLUDED.value, updated_at = CURRENT_TIMESTAMP
            ''', ('last_vanomasa', today))

        logger.warning("VANOMASA: All balances reset to zero!")
        return True

    def get_setting(self, key: str) -> str:
        with get_conn() as conn:
            cur = conn.cursor(cursor_factory=psycopg2.extras.RealDictCursor)
            cur.execute('SELECT value FROM economy_settings WHERE key = %s', (key,))
            result = cur.fetchone()
        return result['value'] if result else '0'

    def update_setting(self, key: str, value: str):
        with get_conn() as conn:
            cur = conn.cursor()
            cur.execute('''
                INSERT INTO economy_settings (key, value, updated_at) VALUES (%s, %s, CURRENT_TIMESTAMP)
                ON CONFLICT (key) DO UPDATE SET value = EXCLUDED.value, updated_at = CURRENT_TIMESTAMP
            ''', (key, value))

    def get_user_stats(self, user_id: int) -> Dict:
        today = datetime.now().strftime('%Y-%m-%d')
        yesterday = (datetime.now() - timedelta(days=1)).strftime('%Y-%m-%d')

        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()
            balance = row['balance'] if row else 0.0

            cur.execute('''
                SELECT COUNT(*) AS cnt, COALESCE(SUM(amount), 0) AS total
                FROM deposits WHERE user_id = %s AND is_active = TRUE
            ''', (user_id,))
            deposits = cur.fetchone()

            cur.execute('''
                SELECT COUNT(*) AS cnt, COALESCE(SUM(amount), 0) AS total
                FROM loans WHERE user_id = %s AND is_repaid = FALSE
            ''', (user_id,))
            loans = cur.fetchone()

            cur.execute(
                'SELECT message_count FROM daily_activity WHERE user_id = %s AND activity_date = %s',
                (user_id, today),
            )
            today_row = cur.fetchone()

            cur.execute(
                'SELECT message_count FROM daily_activity WHERE user_id = %s AND activity_date = %s',
                (user_id, yesterday),
            )
            yesterday_row = cur.fetchone()

        return {
            'balance': balance,
            'active_deposits_count': deposits['cnt'] or 0,
            'active_deposits_sum': deposits['total'] or 0.0,
            'active_loans_count': loans['cnt'] or 0,
            'active_loans_sum': loans['total'] or 0.0,
            'today_messages': today_row['message_count'] if today_row else 0,
            'yesterday_messages': yesterday_row['message_count'] if yesterday_row else 0,
        }

    def regulate_inflation(self):
        inflation_rate = float(self.get_setting('inflation_rate'))

        with get_conn() as conn:
            cur = conn.cursor(cursor_factory=psycopg2.extras.RealDictCursor)
            cur.execute('SELECT SUM(balance) AS total_balance, COUNT(*) AS user_count FROM user_balances')
            result = cur.fetchone()
            total_supply = result['total_balance'] or 0.0

            cur.execute('SELECT capital FROM central_bank WHERE id = 1')
            cb_result = cur.fetchone()
            cb_capital = cb_result['capital'] if cb_result else 1000.0

        if inflation_rate > 10.0 and total_supply > 1000 and cb_capital > 100:
            buyback_amount = min(total_supply * 0.05, cb_capital * 0.1)
            self.update_central_bank(-buyback_amount, 'inflation', f'Anti-inflation: {buyback_amount:.2f} cm')
            new_tax_rate = min(20.0, 13.0 + (inflation_rate - 10.0) * 0.5)
            self.update_setting('tax_rate', str(new_tax_rate))
            logger.info(f"Inflation regulation: bought back {buyback_amount:.2f} cm, tax={new_tax_rate}%")

        elif inflation_rate < 2.0 and total_supply < 500 and cb_capital > 200:
            emission_amount = cb_capital * 0.05
            self.update_central_bank(-emission_amount, 'emission', f'Stimulus: {emission_amount:.2f} cm')
            new_tax_rate = max(10.0, 13.0 - (2.0 - inflation_rate) * 1.5)
            self.update_setting('tax_rate', str(new_tax_rate))
            logger.info(f"Economic stimulus: emitted {emission_amount:.2f} cm, tax={new_tax_rate}%")

    def play_penis(self, user_id: int, display_name: str, now_ts: int,
                   start_length: float, cooldown_seconds: int,
                   min_delta: float, max_delta: float) -> dict:
        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()
            current_balance = row['balance'] if row else start_length

            cur.execute(
                'SELECT last_used_ts, display_name FROM penis_stats WHERE user_id = %s',
                (user_id,),
            )
            ps_row = cur.fetchone()
            last_used_ts = ps_row['last_used_ts'] if ps_row else None

            if last_used_ts is not None:
                next_ts = int(last_used_ts) + cooldown_seconds
                if now_ts < next_ts:
                    if ps_row and ps_row['display_name'] != display_name:
                        wcur = conn.cursor()
                        wcur.execute(
                            'UPDATE penis_stats SET display_name = %s WHERE user_id = %s',
                            (display_name, user_id),
                        )
                    return {'allowed': False, 'left_seconds': next_ts - now_ts}

            delta = round(random.uniform(min_delta, max_delta), 1)
            sign = random.choice([-1, 1])
            new_balance = round(max(0.1, current_balance + sign * delta), 1)

            wcur = conn.cursor()
            wcur.execute('''
                INSERT INTO user_balances (user_id, balance, daily_income, last_daily_reset)
                VALUES (%s, %s, 0.0, CURRENT_DATE)
                ON CONFLICT (user_id) DO UPDATE SET balance = %s
            ''', (user_id, new_balance, new_balance))

            sign_label = f'+{delta:.1f}' if sign > 0 else f'-{delta:.1f}'
            wcur.execute('''
                INSERT INTO transactions (from_user_id, to_user_id, amount, transaction_type, description)
                VALUES (%s, %s, %s, 'penis_game', %s)
            ''', (user_id, user_id, sign * delta, f'Игра /penis: {sign_label} см'))

            if ps_row is None:
                wcur.execute(
                    'INSERT INTO penis_stats (user_id, display_name, last_used_ts) VALUES (%s, %s, %s)',
                    (user_id, display_name, now_ts),
                )
            else:
                wcur.execute(
                    'UPDATE penis_stats SET display_name = %s, last_used_ts = %s WHERE user_id = %s',
                    (display_name, now_ts, user_id),
                )

            return {'allowed': True, 'new_balance': new_balance, 'delta': delta, 'sign': sign}

    def get_penis_top(self, limit: int) -> list:
        with get_conn() as conn:
            cur = conn.cursor(cursor_factory=psycopg2.extras.RealDictCursor)
            cur.execute('''
                SELECT ub.user_id, ps.display_name, ub.balance
                FROM user_balances ub
                INNER JOIN penis_stats ps ON ub.user_id = ps.user_id
                ORDER BY ub.balance DESC, ub.user_id ASC
                LIMIT %s
            ''', (limit,))
            rows = cur.fetchall()
        return [{'user_id': r['user_id'], 'display_name': r['display_name'], 'balance': r['balance']}
                for r in rows]

    def process_matured_deposits(self) -> int:
        with get_conn() as conn:
            cur = conn.cursor(cursor_factory=psycopg2.extras.RealDictCursor)
            cur.execute('''
                SELECT id, user_id, amount, interest_rate
                FROM deposits
                WHERE is_active = TRUE AND matures_at <= NOW()
            ''')
            matured = cur.fetchall()

            paid = 0
            wcur = conn.cursor()
            for row in matured:
                dep_id = row['id']
                user_id = row['user_id']
                amount = row['amount']
                rate = row['interest_rate']
                payout = round(amount * (1 + rate / 100 * 1 / 365 * 30), 2)

                wcur.execute('''
                    INSERT INTO user_balances (user_id, balance, daily_income, last_daily_reset)
                    VALUES (%s, %s, 0.0, CURRENT_DATE)
                    ON CONFLICT (user_id) DO UPDATE SET balance = user_balances.balance + %s
                ''', (user_id, payout, payout))
                wcur.execute('''
                    UPDATE central_bank SET capital = capital - %s, last_updated = CURRENT_TIMESTAMP
                    WHERE id = 1
                ''', (payout,))
                wcur.execute('UPDATE deposits SET is_active = FALSE WHERE id = %s', (dep_id,))
                wcur.execute('''
                    INSERT INTO transactions (from_user_id, to_user_id, amount, transaction_type, description)
                    VALUES (0, %s, %s, 'deposit_payout', %s)
                ''', (user_id, payout, f'Выплата вклада #{dep_id}: {amount:.1f} + проценты = {payout:.2f} см'))
                paid += 1

        if paid:
            logger.info(f"Matured deposits paid out: {paid}")
        return paid


economy = EconomyManager()
