#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
Nano Banana Telegram Bot с генерацией изображений через Gemini 2.5 Flash Image
"""

import os
import logging
import asyncio
import time
from typing import List, Dict, Any, Optional
from datetime import datetime, timedelta
import json
import base64
import requests
import re
import tempfile

import aiohttp
import aiofiles
import io
import google.generativeai as genai
import speech_recognition as sr
import pydub
from pydub import AudioSegment
from PIL import Image
from telegram import Update, Message, InlineKeyboardButton, InlineKeyboardMarkup
from telegram.ext import (
    Application, 
    CommandHandler, 
    MessageHandler, 
    ContextTypes,
    CallbackQueryHandler,
    filters
)
from telegram.constants import ParseMode
from telegram.error import TelegramError, NetworkError, TimedOut
from dotenv import load_dotenv

from config import Config
from bot_analytics import BotAnalytics

# Загружаем переменные окружения
load_dotenv()

# Настройка подробного логирования
logging.basicConfig(
    format='%(asctime)s - %(name)s - %(levelname)s - %(funcName)s:%(lineno)d - %(message)s',
    level=logging.INFO,  # Было DEBUG, теперь INFO
    handlers=[
        logging.StreamHandler(),
        logging.FileHandler('nano_banana_bot.log', encoding='utf-8')
    ]
)
logger = logging.getLogger(__name__)

# Оставляем стандартные уровни для сторонних библиотек,
# убираем явную установку DEBUG
logging.getLogger('telegram').setLevel(logging.WARNING)
logging.getLogger('httpx').setLevel(logging.WARNING)
logging.getLogger('aiohttp').setLevel(logging.WARNING)

class NanoBananaBot:
    def __init__(self):
        logger.info("🤖 ИНИЦИАЛИЗАЦИЯ NANO BANANA BOT...")
        logger.debug(f"🔑 Токен бота: {os.getenv('TELEGRAM_BOT_TOKEN', 'НЕ НАЙДЕН')[:20]}...")
        logger.debug(f"🔑 Gemini ключ: {os.getenv('NANO_BANANA_API_KEY', 'НЕ НАЙДЕН')[:20]}...")
        
        # Обязательная подписка на канал
        self.required_channel = "@MagomedNaurbiev"
        self.required_channel_id = "@MagomedNaurbiev"  # ID канала для проверки
        
        # Ограничения на генерации
        self.daily_limits = {}  # Словарь для хранения лимитов пользователей
        self.max_generations_per_day = 10  # Максимум генераций в день
        self.exempt_users = ['valeri_look', 'naurbievm']  # Пользователи без ограничений
        
        # Инициализируем модуль аналитики
        self.analytics = BotAnalytics(db_path="/var/www/u0236315/data/www/consultsolution.ru/bot_illustrator.db")
        
        # Проверяем конфигурацию
        if not Config.validate():
            logger.error("❌ Ошибка конфигурации!")
            raise ValueError("Ошибка конфигурации. Проверьте переменные окружения.")
        
        self.bot_token = Config.TELEGRAM_BOT_TOKEN
        self.nano_banana_url = Config.NANO_BANANA_API_URL
        self.nano_banana_key = Config.NANO_BANANA_API_KEY
        
        # Настраиваем прокси для обхода блокировки Google
        self.setup_proxy()
        
        # Настраиваем Google Generative AI
        try:
            genai.configure(api_key=self.nano_banana_key)
            self.model = None  # Используем только прямые HTTP запросы
        except Exception as e:
            logger.warning(f"⚠️ Google Gemini API недоступен: {e}")
            self.model = None
        
        # Создаем папку для временных файлов
        os.makedirs(Config.TEMP_PHOTOS_DIR, exist_ok=True)
        
        # Добавляем словари для функции "Изменить"
        self.last_generations = {}  # Хранение последних сгенерированных изображений
        self.user_albums = {}  # Для альбомов
        self.waiting_for_modification = {}  # Пользователи, ожидающие ввода нового промпта
        
        logger.info("🤖 NanoBananaBot инициализирован успешно")

    async def check_subscription(self, user_id: int, context: ContextTypes.DEFAULT_TYPE) -> bool:
        """Проверка подписки пользователя на обязательный канал"""
        try:
            # Получаем информацию о пользователе для проверки исключений
            user = await context.bot.get_chat(user_id)
            username = getattr(user, 'username', None)
            
            # Исключения - пользователи, которые могут пользоваться ботом без подписки
            exempt_users = ['valeri_look']  # Список пользователей-исключений
            
            if username and username.lower() in exempt_users:
                logger.info(f"✅ Пользователь @{username} в списке исключений - доступ разрешен")
                return True
            
            member = await context.bot.get_chat_member(self.required_channel_id, user_id)
            # Проверяем статус пользователя в канале
            if member.status in ['member', 'administrator', 'creator']:
                return True
            else:
                return False
        except Exception as e:
            logger.error(f"❌ Ошибка проверки подписки для пользователя {user_id}: {e}")
            # В случае ошибки (например, канал недоступен), разрешаем доступ
            return True

    async def send_subscription_required_message(self, user_id: int, context: ContextTypes.DEFAULT_TYPE):
        """Отправляет сообщение о необходимости подписки"""
        keyboard = InlineKeyboardMarkup([
            [InlineKeyboardButton("📢 Подписаться на канал", url=f"https://t.me/{self.required_channel[1:]}")],
            [InlineKeyboardButton("✅ Проверить подписку", callback_data="check_subscription")]
        ])
        
        message = f"""🔒 **Доступ ограничен**

Для использования бота необходимо подписаться на канал:
👉 **{self.required_channel}**

После подписки нажмите кнопку "Проверить подписку" ниже.

🎨 **Что вас ждет после подписки:**
• Генерация изображений по тексту
• Создание изображений по фото-референсам  
• Модификация существующих изображений
• Работа с альбомами фотографий"""

        await context.bot.send_message(
            chat_id=user_id,
            text=message,
            reply_markup=keyboard,
            parse_mode=ParseMode.MARKDOWN
        )

    def get_user_username(self, user_id: int, context: ContextTypes.DEFAULT_TYPE, update=None) -> str:
        """Получает username пользователя"""
        try:
            # Пытаемся получить из переданного update
            if update and hasattr(update, 'effective_user') and update.effective_user:
                return update.effective_user.username
            
            # Пытаемся получить из context.update, если доступен
            if hasattr(context, 'update') and context.update and hasattr(context.update, 'effective_user'):
                return context.update.effective_user.username
            
            # Пытаемся получить из контекста, если доступен
            if hasattr(context, 'user_data') and 'username' in context.user_data:
                return context.user_data['username']
            
            return None
        except:
            return None

    def is_user_exempt(self, user_id: int, context: ContextTypes.DEFAULT_TYPE, update=None) -> bool:
        """Проверяет, является ли пользователь исключением"""
        try:
            # Сначала проверяем по username
            username = self.get_user_username(user_id, context, update)
            if username and username.lower() in self.exempt_users:
                logger.info(f"✅ Пользователь @{username} найден в списке исключений")
                return True
            
            # Если username недоступен, проверяем по user_id (для @valeri_look)
            # Это запасной вариант, если username не удается получить
            if user_id == 123456789:  # Замените на реальный user_id @valeri_look
                logger.info(f"✅ Пользователь {user_id} найден в списке исключений по ID")
                return True
            
            return False
        except Exception as e:
            logger.error(f"❌ Ошибка проверки исключения для пользователя {user_id}: {e}")
            return False

    def check_daily_limit(self, user_id: int, context: ContextTypes.DEFAULT_TYPE, update=None) -> bool:
        """Проверяет, не превышен ли дневной лимит генераций"""
        try:
            # Проверяем, является ли пользователь исключением
            if self.is_user_exempt(user_id, context, update):
                logger.info(f"✅ Пользователь {user_id} в списке исключений - лимиты не применяются")
                return True
            
            # Получаем текущую дату
            from datetime import datetime
            today = datetime.now().strftime('%Y-%m-%d')
            
            # Инициализируем лимиты для пользователя, если их нет
            if user_id not in self.daily_limits:
                self.daily_limits[user_id] = {'date': today, 'count': 0}
            
            # Если дата изменилась, сбрасываем счетчик
            if self.daily_limits[user_id]['date'] != today:
                self.daily_limits[user_id] = {'date': today, 'count': 0}
            
            # Проверяем лимит
            current_count = self.daily_limits[user_id]['count']
            if current_count >= self.max_generations_per_day:
                logger.info(f"🚫 Пользователь {user_id} превысил дневной лимит: {current_count}/{self.max_generations_per_day}")
                return False
            
            return True
        except Exception as e:
            logger.error(f"❌ Ошибка проверки лимита для пользователя {user_id}: {e}")
            return True  # В случае ошибки разрешаем генерацию

    def increment_daily_limit(self, user_id: int, context: ContextTypes.DEFAULT_TYPE, update=None):
        """Увеличивает счетчик генераций для пользователя"""
        try:
            # Проверяем, является ли пользователь исключением
            if self.is_user_exempt(user_id, context, update):
                return  # Для исключений не считаем
            
            # Получаем текущую дату
            from datetime import datetime
            today = datetime.now().strftime('%Y-%m-%d')
            
            # Инициализируем лимиты для пользователя, если их нет
            if user_id not in self.daily_limits:
                self.daily_limits[user_id] = {'date': today, 'count': 0}
            
            # Если дата изменилась, сбрасываем счетчик
            if self.daily_limits[user_id]['date'] != today:
                self.daily_limits[user_id] = {'date': today, 'count': 0}
            
            # Увеличиваем счетчик
            self.daily_limits[user_id]['count'] += 1
            logger.info(f"📊 Пользователь {user_id}: {self.daily_limits[user_id]['count']}/{self.max_generations_per_day} генераций сегодня")
        except Exception as e:
            logger.error(f"❌ Ошибка обновления лимита для пользователя {user_id}: {e}")

    async def send_limit_exceeded_message(self, user_id: int, context: ContextTypes.DEFAULT_TYPE):
        """Отправляет сообщение о превышении лимита"""
        message = f"""🚫 <b>Дневной лимит превышен</b>

Вы использовали все {self.max_generations_per_day} генераций на сегодня.

⏰ <b>Лимит обновится завтра</b>
🔄 <b>Попробуйте снова после 00:00</b>

💡 <b>Совет:</b> Подпишитесь на канал {self.required_channel} для получения уведомлений о новых возможностях!"""

        await context.bot.send_message(
            chat_id=user_id,
            text=message,
            parse_mode='HTML'
        )

    async def convert_voice_to_text(self, voice_file_path: str) -> str:
        """Преобразует голосовое сообщение в текст"""
        try:
            logger.info(f"🎤 Начинаем преобразование голоса в текст: {voice_file_path}")
            
            # Инициализируем распознаватель речи
            recognizer = sr.Recognizer()
            
            # Загружаем аудиофайл
            audio = AudioSegment.from_file(voice_file_path)
            
            # Конвертируем в формат WAV для лучшего распознавания
            wav_path = voice_file_path.replace('.ogg', '.wav')
            audio.export(wav_path, format="wav")
            
            # Распознаем речь
            with sr.AudioFile(wav_path) as source:
                audio_data = recognizer.record(source)
                
            # Используем Google Speech Recognition
            text = recognizer.recognize_google(audio_data, language='ru-RU')
            
            # Удаляем временные файлы
            if os.path.exists(wav_path):
                os.remove(wav_path)
            
            logger.info(f"✅ Голос успешно преобразован в текст: {text}")
            return text
            
        except sr.UnknownValueError:
            logger.error("❌ Не удалось распознать речь")
            return None
        except sr.RequestError as e:
            logger.error(f"❌ Ошибка сервиса распознавания речи: {e}")
            return None
        except Exception as e:
            logger.error(f"❌ Ошибка при преобразовании голоса в текст: {e}")
            return None

    def setup_proxy(self):
        """Настройка прокси для обхода блокировки Google в России"""
        try:
            if Config.USE_PROXY:
                proxy_url = f"http://{Config.PROXY_LOGIN}:{Config.PROXY_PASS}@{Config.PROXY_SERVER}:{Config.PROXY_PORT}"
                os.environ["HTTP_PROXY"] = proxy_url
                os.environ["HTTPS_PROXY"] = proxy_url
                
                # Создаем кастомный HTTP клиент
                self.gemini_session = requests.Session()
                self.gemini_session.proxies = {
                    'http': proxy_url,
                    'https': proxy_url
                }
                
                self.gemini_session.headers.update({
                    'Content-Type': 'application/json',
                    'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) Chrome/120.0.0.0',
                    'Accept-Language': 'en-US,en;q=0.9',
                    'Origin': 'https://aistudio.google.com',
                    'Referer': 'https://aistudio.google.com/',
                    'X-Forwarded-For': '185.199.108.153'
                })
                
                self.gemini_base_url = "https://generativelanguage.googleapis.com/v1beta/models"
                logger.info("✅ Прокси настроен успешно для Google Gemini API")
                
                # Тестируем прокси
                try:
                    test_response = self.gemini_session.get('https://httpbin.org/ip', timeout=10)
                    if test_response.status_code == 200:
                        ip_info = test_response.json()
                        logger.info(f"✅ Прокси работает! IP: {ip_info.get('origin', 'неизвестно')}")
                    else:
                        logger.warning(f"⚠️ Прокси тест вернул статус: {test_response.status_code}")
                except Exception as proxy_test_error:
                    logger.warning(f"⚠️ Не удалось протестировать прокси: {proxy_test_error}")
            else:
                logger.info("🔍 Прокси отключен в конфигурации")
                self.gemini_session = None
                
        except Exception as e:
            logger.error(f"❌ Ошибка настройки прокси: {e}")
            self.gemini_session = None

    def generate_image_with_gemini(self, prompt: str) -> Dict[str, Any]:
        """Генерация изображения через Gemini 2.5 Flash Image API"""
        try:
            if not self.gemini_session:
                raise Exception("HTTP клиент не инициализирован")
            
            logger.info(f"🎨 Генерация изображения через Gemini 2.5 Flash Image: {prompt}")
            
            # Подготавливаем запрос для генерации изображения
            parts = [{"text": f"Create a detailed, high-quality image of: {prompt}"}]
            
            request_data = {
                "contents": [{"parts": parts}],
                "generationConfig": {
                    "temperature": 0.7,
                    "maxOutputTokens": 32768
                }
            }
            
            # Используем правильную модель для генерации изображений
            url = f"{self.gemini_base_url}/gemini-2.5-flash-image:generateContent?key={self.nano_banana_key}"
            response = self.gemini_session.post(url, json=request_data, timeout=120)
            
            if response.status_code == 200:
                result = response.json()
                logger.info(f"🔍 Полный ответ от Gemini Image API получен")
                
                if 'candidates' in result and result['candidates']:
                    candidate = result['candidates'][0]
                    if 'content' in candidate and 'parts' in candidate['content']:
                        
                        # Ищем изображение в ответе
                        for part in candidate['content']['parts']:
                            if 'inlineData' in part and part['inlineData'].get('mimeType', '').startswith('image/'):
                                image_data = part['inlineData'].get('data')
                                if image_data:
                                    logger.info(f"✅ Изображение получено! Размер: {len(image_data)} символов base64")
                                    return {
                                        'success': True,
                                        'image_data': image_data,
                                        'generated_text': f"🎨 Изображение сгенерировано по запросу:\n<b>«{prompt}»</b>",
                                        'original_prompt': prompt
                                    }
                            elif 'text' in part:
                                logger.info(f"📝 Текстовый ответ: {part['text'][:100]}...")
                        
                        return {
                            'success': False,
                            'error': 'Не удалось сгенерировать изображение. Попробуйте еще раз и запросите немного иначе'
                        }
                
                return {
                    'success': False,
                    'error': 'Не удалось сгенерировать изображение. Попробуйте еще раз и запросите немного иначе'
                }
            else:
                error_text = response.text
                logger.error(f"❌ Ошибка Gemini Image API: {response.status_code} - {error_text}")
                
                if response.status_code == 400:
                    return {
                        'success': False,
                        'error': 'Некорректный запрос к Gemini Image API'
                    }
                elif response.status_code == 403:
                    return {
                        'success': False,
                        'error': 'Доступ к Gemini Image API запрещен (проверьте API ключ)'
                    }
                elif response.status_code == 429:
                    return {
                        'success': False,
                        'error': 'Превышен лимит запросов к Gemini Image API'
                    }
                else:
                    return {
                        'success': False,
                        'error': f'Ошибка Gemini Image API: {response.status_code}'
                    }
                
        except Exception as e:
            logger.error(f"❌ Ошибка генерации изображения через Gemini: {e}")
            return {
                'success': False,
                'error': str(e)
            }

    def call_gemini_api_direct(self, prompt: str, images: List[Image.Image] = None) -> Dict[str, Any]:
        """Прямой вызов Gemini API для анализа через прокси"""
        try:
            if not self.gemini_session:
                raise Exception("HTTP клиент не инициализирован")
            
            # Подготавливаем части запроса
            parts = [{"text": prompt}]
            
            # Добавляем изображения, если есть
            if images:
                for image in images:
                    # Конвертируем изображение в base64
                    buffer = io.BytesIO()
                    image.save(buffer, format='JPEG')
                    image_data = buffer.getvalue()
                    image_base64 = base64.b64encode(image_data).decode('utf-8')
                    
                    parts.append({
                        "inline_data": {
                            "mime_type": "image/jpeg",
                            "data": image_base64
                        }
                    })
            
            request_data = {
                "contents": [{"parts": parts}],
                "generationConfig": {
                    "temperature": 0.7,
                    "maxOutputTokens": 2048
                }
            }
            
            # Отправляем запрос
            url = f"{self.gemini_base_url}/gemini-2.0-flash-exp:generateContent?key={self.nano_banana_key}"
            response = self.gemini_session.post(url, json=request_data, timeout=60)
            
            if response.status_code == 200:
                result = response.json()
                if 'candidates' in result and result['candidates']:
                    candidate = result['candidates'][0]
                    if 'content' in candidate and 'parts' in candidate['content']:
                        text_parts = []
                        for part in candidate['content']['parts']:
                            if 'text' in part:
                                text_parts.append(part['text'])
                        
                        if text_parts:
                            return {
                                'success': True,
                                'text': '\n'.join(text_parts)
                            }
                
                return {
                    'success': False,
                    'error': 'Пустой ответ от API'
                }
            else:
                return {
                    'success': False,
                    'error': f'HTTP {response.status_code}: {response.text}'
                }
                
        except Exception as e:
            logger.error(f"❌ Ошибка прямого вызова Gemini API: {e}")
            return {
                'success': False,
                'error': str(e)
            }

    async def start_command(self, update: Update, context: ContextTypes.DEFAULT_TYPE) -> None:
        """Обработчик команды /start с проверкой подписки"""
        user_id = update.effective_user.id
        user_name = update.effective_user.first_name or "Пользователь"
        username = update.effective_user.username
        last_name = update.effective_user.last_name
        
        logger.info(f"👤 Пользователь {user_id} ({user_name}) запустил бота")
        
        # Сохраняем пользователя в базу данных
        self.save_user(user_id)
        
        # Регистрируем в аналитике
        self.analytics.register_user(user_id, username, user_name, last_name)
        
        # Проверяем подписку на канал
        is_subscribed = await self.check_subscription(user_id, context)
        
        if not is_subscribed:
            logger.info(f"🔒 Пользователь {user_id} не подписан на канал {self.required_channel}")
            await self.send_subscription_required_message(user_id, context)
            return
        
        # Если подписан, показываем приветствие с логотипом
        try:
            # Отправляем логотип
            logo_path = "/var/www/u0236315/data/www/consultsolution.ru/logo.jpeg"
            if os.path.exists(logo_path):
                with open(logo_path, 'rb') as logo_file:
                    await update.message.reply_photo(
                        photo=logo_file,
                        caption=Config.get_message('welcome'),
                        parse_mode='HTML'
                    )
                logger.info(f"✅ Пользователь {user_id} подписан - доступ разрешен с логотипом")
            else:
                # Если логотип не найден, отправляем только текст
                await update.message.reply_text(Config.get_message('welcome'), parse_mode='HTML')
                logger.info(f"✅ Пользователь {user_id} подписан - доступ разрешен (логотип не найден)")
        except TelegramError as e:
            logger.error(f"Ошибка при отправке приветственного сообщения: {e}")
        except Exception as e:
            logger.error(f"Неожиданная ошибка в start_command: {e}")

    async def analytics_command(self, update: Update, context: ContextTypes.DEFAULT_TYPE) -> None:
        """Обработчик команды /analytics для вывода аналитики"""
        user_id = update.effective_user.id
        
        # Проверяем, что это администратор
        if user_id not in [int(admin_id) for admin_id in Config.ADMIN_IDS]:
            await update.message.reply_text("❌ У вас нет прав для выполнения этой команды")
            return
        
        try:
            # Отправляем сообщение о загрузке
            loading_msg = await update.message.reply_text("📊 Формирую аналитику...")
            
            # Получаем отформатированную аналитику
            analytics_message = self.analytics.format_analytics_message()
            
            # Отправляем аналитику
            await loading_msg.edit_text(analytics_message, parse_mode='HTML')
            
            logger.info(f"✅ Аналитика отправлена администратору {user_id}")
            
        except Exception as e:
            logger.error(f"❌ Ошибка при отправке аналитики: {e}")
            await update.message.reply_text(f"❌ Ошибка при формировании аналитики: {e}")
    
    async def broadcast_command(self, update: Update, context: ContextTypes.DEFAULT_TYPE) -> None:
        """Обработчик команды /broadcast для массовой рассылки"""
        user_id = update.effective_user.id
        
        # Проверяем, что это администратор
        if user_id not in [int(admin_id) for admin_id in Config.ADMIN_IDS]:
            await update.message.reply_text("❌ У вас нет прав для выполнения этой команды")
            return
        
        # Получаем текст сообщения
        message_text = update.message.text.replace('/broadcast', '').strip()
        
        if not message_text:
            await update.message.reply_text("❌ Укажите текст для рассылки\nПример: /broadcast Привет всем!")
            return
        
        # Подтверждение рассылки
        keyboard = [
            [InlineKeyboardButton("✅ Да, отправить", callback_data=f"confirm_broadcast:{message_text}")],
            [InlineKeyboardButton("❌ Отмена", callback_data="cancel_broadcast")]
        ]
        reply_markup = InlineKeyboardMarkup(keyboard)
        
        await update.message.reply_text(
            f"📢 Подтвердите рассылку сообщения:\n\n{message_text}",
            reply_markup=reply_markup
        )

    async def send_broadcast_message(self, message_text: str, context: ContextTypes.DEFAULT_TYPE) -> None:
        """Отправка массовой рассылки всем подписчикам"""
        try:
            # Получаем список всех пользователей из базы данных
            users = self.get_all_users()
            total_users = len(users)
            successful_sends = 0
            failed_sends = 0
            
            logger.info(f"📢 Начинаем рассылку сообщения {total_users} пользователям")
            
            for user_id in users:
                try:
                    await context.bot.send_message(
                        chat_id=user_id,
                        text=message_text,
                        parse_mode='HTML'
                    )
                    successful_sends += 1
                    logger.info(f"✅ Сообщение отправлено пользователю {user_id}")
                    
                    # Небольшая задержка между отправками
                    await asyncio.sleep(0.1)
                    
                except TelegramError as e:
                    failed_sends += 1
                    logger.error(f"❌ Ошибка отправки пользователю {user_id}: {e}")
                    continue
                except Exception as e:
                    failed_sends += 1
                    logger.error(f"❌ Неожиданная ошибка для пользователя {user_id}: {e}")
                    continue
            
            # Отправляем отчет администратору
            report = f"📊 Отчет о рассылке:\n\n"
            report += f"👥 Всего пользователей: {total_users}\n"
            report += f"✅ Успешно отправлено: {successful_sends}\n"
            report += f"❌ Ошибок: {failed_sends}\n"
            report += f"📈 Процент успеха: {(successful_sends/total_users*100):.1f}%"
            
            for admin_id in Config.ADMIN_IDS:
                try:
                    await context.bot.send_message(chat_id=admin_id, text=report)
                except Exception as e:
                    logger.error(f"Ошибка отправки отчета администратору {admin_id}: {e}")
                    
        except Exception as e:
            logger.error(f"❌ Критическая ошибка при рассылке: {e}")

    def get_all_users(self) -> List[int]:
        """Получение списка всех пользователей из базы данных"""
        try:
            users_file = "/var/www/u0236315/data/www/consultsolution.ru/users.json"
            if os.path.exists(users_file):
                with open(users_file, 'r', encoding='utf-8') as f:
                    users_data = json.load(f)
                    return users_data.get('users', [])
            else:
                logger.warning("Файл пользователей не найден")
                return []
        except Exception as e:
            logger.error(f"Ошибка получения списка пользователей: {e}")
            return []

    def save_user(self, user_id: int) -> None:
        """Сохранение пользователя в базу данных"""
        try:
            users_file = "/var/www/u0236315/data/www/consultsolution.ru/users.json"
            users_data = {'users': []}
            
            if os.path.exists(users_file):
                with open(users_file, 'r', encoding='utf-8') as f:
                    users_data = json.load(f)
            
            if user_id not in users_data.get('users', []):
                users_data.setdefault('users', []).append(user_id)
                
                with open(users_file, 'w', encoding='utf-8') as f:
                    json.dump(users_data, f, ensure_ascii=False, indent=2)
                    
                logger.info(f"Пользователь {user_id} сохранен в базу данных")
        except Exception as e:
            logger.error(f"Ошибка сохранения пользователя {user_id}: {e}")

    async def handle_text_message(self, update: Update, context: ContextTypes.DEFAULT_TYPE) -> None:
        user_id = update.effective_user.id
        text = update.message.text.strip()
        
        # Регистрируем пользователя в аналитике
        self.analytics.register_user(
            user_id, 
            update.effective_user.username,
            update.effective_user.first_name,
            update.effective_user.last_name
        )
        
        # Создаём сообщение о процессе генерации
        processing_message = await context.bot.send_message(
            chat_id=user_id,
            text="🎨 Генерирую изображение...",
            parse_mode='HTML'
        )
        
        prompt, file_mode, clean_text = self.get_generation_strategy(text)
        logger.info(f"[TEXT] user={user_id} original='{text}' mode={'file' if file_mode else 'photo'} clean='{clean_text}'")
        result = self.generate_image_with_gemini(prompt)
        
        # Логируем генерацию
        self.analytics.log_generation(user_id, 'text', text, result.get('success', False))
        if file_mode and result.get('success') and result.get('image_data'):
            image_bytes = base64.b64decode(result['image_data'])
            with tempfile.NamedTemporaryFile(suffix='.jpg', delete=False) as tmpfile:
                tmpfile.write(image_bytes)
                tmpfile_path = tmpfile.name
            await context.bot.send_document(
                chat_id=user_id,
                document=open(tmpfile_path, 'rb'),
                filename='generated_image.jpg',
                caption=clean_text,
                parse_mode='HTML'
            )
            os.remove(tmpfile_path)
            # Удаляем сообщение о процессе
            await processing_message.delete()
            return
        # стандартное поведение — квадрат send_photo
        await self.send_generation_result(user_id, result, processing_message, context, update)

    async def handle_voice_message(self, update: Update, context: ContextTypes.DEFAULT_TYPE) -> None:
        """Обработчик голосовых сообщений - преобразование в текст и генерация изображений"""
        user_id = update.effective_user.id
        voice = update.message.voice
        
        # Регистрируем пользователя в аналитике
        self.analytics.register_user(
            user_id, 
            update.effective_user.username,
            update.effective_user.first_name,
            update.effective_user.last_name
        )
        
        logger.info(f"🎤 ПОЛУЧЕНО ГОЛОСОВОЕ СООБЩЕНИЕ от пользователя {user_id}")
        
        # Проверяем подписку на канал
        is_subscribed = await self.check_subscription(user_id, context)
        if not is_subscribed:
            logger.info(f"🔒 Пользователь {user_id} не подписан на канал {self.required_channel}")
            await self.send_subscription_required_message(user_id, context)
            return
        
        # Проверяем дневной лимит генераций
        if not self.check_daily_limit(user_id, context, update):
            logger.info(f"🚫 Пользователь {user_id} превысил дневной лимит генераций")
            await self.send_limit_exceeded_message(user_id, context)
            return
        
        # Отправляем сообщение о начале обработки голоса
        processing_message = await context.bot.send_message(
                        chat_id=user_id,
            text="🎤 Обрабатываю голосовое сообщение...\n⏳ Скоро пришлю результат"
                    )
                    
        # Автоматически удаляем сообщение через 3 секунды
        async def delete_processing_message():
            await asyncio.sleep(3)
            try:
                    await processing_message.delete()
            except Exception as e:
                logger.debug(f"Не удалось удалить сообщение обработки: {e}")
        
        # Запускаем задачу удаления в фоне
        asyncio.create_task(delete_processing_message())
        
        try:
            # Скачиваем голосовое сообщение
            voice_file = await context.bot.get_file(voice.file_id)
            voice_path = f"/tmp/voice_{user_id}_{int(time.time())}.ogg"
            
            await voice_file.download_to_drive(voice_path)
            logger.info(f"📥 Голосовое сообщение скачано: {voice_path}")
            
            # Преобразуем голос в текст
            text = await self.convert_voice_to_text(voice_path)
            
            # Удаляем временный файл
            if os.path.exists(voice_path):
                os.remove(voice_path)
            
            if not text:
                await processing_message.edit_text("❌ Не удалось распознать голосовое сообщение. Попробуйте еще раз или отправьте текстовое описание.")
                return
            
            logger.info(f"📝 Распознанный текст: {text}")
            
            # Проверяем, ожидает ли пользователь ввода нового промпта для модификации
            if user_id in self.waiting_for_modification and self.waiting_for_modification[user_id]:
                logger.info(f"🔄 Пользователь {user_id} в режиме модификации (голос)")
                await self.handle_modification_prompt(update, context, text)
                return
            
            # Обновляем сообщение о начале генерации
            await processing_message.edit_text("🎨 Генерирую изображение...\n⏳ Скоро пришлю результат")
            
            # Генерируем изображение через Gemini 2.5 Flash Image
            result = self.generate_image_with_gemini(text)
            logger.debug(f"📊 Результат генерации: success={result.get('success', False)}, error={result.get('error', 'None')}")
            
            # Логируем генерацию
            self.analytics.log_generation(user_id, 'voice', text, result.get('success', False))
            
            # Отправляем результат
            await self.send_generation_result(user_id, result, processing_message, context, update)
                
        except Exception as e:
            logger.error(f"❌ КРИТИЧЕСКАЯ ОШИБКА при обработке голосового сообщения: {e}", exc_info=True)
            await processing_message.edit_text(f"❌ Произошла критическая ошибка при обработке голоса: {e}\n\nПопробуйте еще раз или отправьте текстовое описание.")

    async def handle_button_callback(self, update: Update, context: ContextTypes.DEFAULT_TYPE) -> None:
        """Обработчик нажатий на кнопки"""
        query = update.callback_query
        await query.answer()
        
        user_id = query.from_user.id
        callback_data = query.data
        
        if callback_data == "check_subscription":
            # Пользователь нажал кнопку "Проверить подписку"
            is_subscribed = await self.check_subscription(user_id, context)
            
            if is_subscribed:
                # Подписка есть - показываем приветствие
                await query.edit_message_text(
                    text="✅ **Отлично! Подписка подтверждена.**\n\n" + Config.get_message('welcome'),
                    parse_mode=ParseMode.MARKDOWN
                )
                logger.info(f"✅ Пользователь {user_id} подтвердил подписку")
            else:
                # Подписки нет - показываем сообщение об ошибке
                await query.edit_message_text(
                    text=f"""❌ **Подписка не найдена**

Пожалуйста, убедитесь, что вы подписались на канал:
👉 **{self.required_channel}**

После подписки нажмите кнопку "Проверить подписку" еще раз.""",
                    reply_markup=InlineKeyboardMarkup([
                        [InlineKeyboardButton("📢 Подписаться на канал", url=f"https://t.me/{self.required_channel[1:]}")],
                        [InlineKeyboardButton("✅ Проверить подписку", callback_data="check_subscription")]
                    ]),
                    parse_mode=ParseMode.MARKDOWN
                )
                logger.info(f"❌ Пользователь {user_id} не подписан при проверке")
            return
        
        elif callback_data.startswith("confirm_broadcast:"):
            # Подтверждение рассылки
            if user_id not in [int(admin_id) for admin_id in Config.ADMIN_IDS]:
                await query.edit_message_text("❌ У вас нет прав для выполнения этой команды")
                return
            
            message_text = callback_data.replace("confirm_broadcast:", "")
            await query.edit_message_text("📢 Рассылка запущена...")
            
            # Запускаем рассылку в фоновом режиме
            asyncio.create_task(self.send_broadcast_message(message_text, context))
            return
            
        elif callback_data == "cancel_broadcast":
            # Отмена рассылки
            await query.edit_message_text("❌ Рассылка отменена")
            return
            
        elif callback_data.startswith("modify_"):
            # Проверяем подписку перед модификацией
            is_subscribed = await self.check_subscription(user_id, context)
            if not is_subscribed:
                await self.send_subscription_required_message(user_id, context)
                return
            
            # Пользователь нажал кнопку "Изменить"
            if user_id in self.last_generations:
                self.waiting_for_modification[user_id] = True
                
                # Отправляем системное сообщение с автоудалением
                system_message = await context.bot.send_message(
                        chat_id=user_id,
                    text="⚡ <b>Режим изменения активирован</b>\n\n📝 Напишите, как изменить изображение или отправьте новое фото с подписью",
                    parse_mode='HTML'
                )
                
                # Планируем удаление системного сообщения через 2 секунды
                context.job_queue.run_once(
                    self.delete_system_message,
                    when=2,
                    data={'chat_id': user_id, 'message_id': system_message.message_id},
                    name=f"delete_system_msg_{user_id}_{system_message.message_id}"
                )
                
                # Кнопка остается на месте, не убираем её
                logger.info(f"👤 Пользователь {user_id} запросил изменение изображения")
            else:
                await context.bot.send_message(
                    chat_id=user_id,
                    text="❌ Не найдено изображение для изменения. Сначала сгенерируйте изображение."
                )
    
    async def delete_system_message(self, context: ContextTypes.DEFAULT_TYPE) -> None:
        """Удаляет системное сообщение"""
        try:
            job_data = context.job.data
            await context.bot.delete_message(
                chat_id=job_data['chat_id'],
                message_id=job_data['message_id']
            )
            logger.info(f"🗑️ Системное сообщение удалено для пользователя {job_data['chat_id']}")
        except Exception as e:
            logger.debug(f"Не удалось удалить системное сообщение: {e}")

    async def handle_modification_prompt(self, update: Update, context: ContextTypes.DEFAULT_TYPE, new_prompt: str) -> None:
        user_id = update.effective_user.id
        prompt, file_mode, clean_text = self.get_generation_strategy(new_prompt)
        logger.info(f"[MODIFY] user={user_id} original='{new_prompt}' mode={'file' if file_mode else 'photo'} clean='{clean_text}'")
        result = self.generate_image_with_gemini(prompt)
        
        # Логируем модификацию
        self.analytics.log_generation(user_id, 'modification', new_prompt, result.get('success', False))
        if file_mode and result.get('success') and result.get('image_data'):
            image_bytes = base64.b64decode(result['image_data'])
            with tempfile.NamedTemporaryFile(suffix='.jpg', delete=False) as tmpfile:
                tmpfile.write(image_bytes)
                tmpfile_path = tmpfile.name
            await context.bot.send_document(
                chat_id=user_id,
                document=open(tmpfile_path, 'rb'),
                filename='generated_image.jpg',
                caption=clean_text,
                parse_mode='HTML'
            )
            os.remove(tmpfile_path)
            return
        else:
            ... # send_photo

    async def handle_photo_with_album_check(self, update: Update, context: ContextTypes.DEFAULT_TYPE) -> None:
        """Универсальный обработчик фотографий - проверяет альбом или одиночное фото"""
        user_id = update.effective_user.id
        message = update.message
        
        # Проверяем подписку на канал
        is_subscribed = await self.check_subscription(user_id, context)
        if not is_subscribed:
            logger.info(f"🔒 Пользователь {user_id} не подписан на канал {self.required_channel}")
            await self.send_subscription_required_message(user_id, context)
            return
        
        # Проверяем дневной лимит генераций
        if not self.check_daily_limit(user_id, context, update):
            logger.info(f"🚫 Пользователь {user_id} превысил дневной лимит генераций")
            await self.send_limit_exceeded_message(user_id, context)
            return
        
        # Проверяем, является ли фото частью альбома
        if message.media_group_id:
            logger.info(f"📸 Фото является частью альбома {message.media_group_id}")
            await self.handle_media_group(update, context)
        else:
            logger.info(f"📸 Получено одиночное фото")
            await self.handle_photo(update, context)

    async def handle_photo(self, update: Update, context: ContextTypes.DEFAULT_TYPE) -> None:
        """Обработчик одиночных фотографий - генерация изображений на основе референсов"""
        user_id = update.effective_user.id
        message = update.message
        
        # Регистрируем пользователя в аналитике
        self.analytics.register_user(
            user_id, 
            update.effective_user.username,
            update.effective_user.first_name,
            update.effective_user.last_name
        )
        
        # Проверяем наличие подписи
        caption = message.caption
        if not caption or not caption.strip():
            # Если пользователь ожидает модификации, обрабатываем фото как новый референс для изменения
            if user_id in self.waiting_for_modification and self.waiting_for_modification[user_id]:
                await message.reply_text("📝 Для изменения изображения на основе нового фото, добавьте подпись с описанием изменений.\n\n**Пример:** Отправьте фото + \"изменить позу как на этом фото\"")
                return
            else:
                await message.reply_text("📝 Пожалуйста, добавьте подпись к фотографии с описанием того, что вы хотите сгенерировать.\n\n🎨 **Пример:** Отправьте фото кота с подписью \"красивый кот в космосе\" - и бот сгенерирует новое изображение в этом стиле!")
            return
        
        # Проверяем, ожидает ли пользователь модификации изображения
        if user_id in self.waiting_for_modification and self.waiting_for_modification[user_id]:
            await self.handle_photo_modification(update, context, caption.strip())
            return
        
        # Одиночное фото - генерируем сразу
        logger.info(f"📸 Получено одиночное фото от пользователя {user_id} для генерации")
        
        processing_message = await message.reply_text("🎨 Генерирую изображение...\n⏳ Скоро пришлю результат")
        
        try:
            # Скачиваем фото
            photo_file = await message.photo[-1].get_file()
            photo_path = f"{Config.TEMP_PHOTOS_DIR}/{user_id}_ref_{time.time()}.jpg"
            await photo_file.download_to_drive(photo_path)
            
            logger.info(f"📸 Референсное фото скачано: {photo_path}")
            
            # Генерируем изображение на основе референса
            result = await self.generate_image_from_reference([photo_path], caption.strip())
            
            # Логируем генерацию
            self.analytics.log_generation(user_id, 'photo', caption.strip(), result.get('success', False))
            
            # Отправляем результат
            await self.send_generation_result(user_id, result, processing_message, context, update)
            
            # Удаляем временный файл
            try:
                os.remove(photo_path)
                logger.info(f"🗑️ Временный файл удален: {photo_path}")
            except Exception as e:
                logger.error(f"Ошибка удаления файла {photo_path}: {e}")
                
        except Exception as e:
            logger.error(f"❌ Ошибка при генерации по референсу: {e}")
            await processing_message.edit_text("❌ Произошла ошибка при генерации изображения. Попробуйте еще раз.")

    async def handle_photo_modification(self, update: Update, context: ContextTypes.DEFAULT_TYPE, modification_text: str) -> None:
        """Обработчик модификации изображения с использованием нового фото как референса"""
        user_id = update.effective_user.id
        message = update.message
        
        if user_id not in self.last_generations:
            await message.reply_text("❌ Не найдено изображение для изменения.")
            self.waiting_for_modification[user_id] = False
            return
        
        # Убираем флаг ожидания
        self.waiting_for_modification[user_id] = False
        
        last_gen = self.last_generations[user_id]
        current_image_data = last_gen.get('image_data', '')
        
        processing_message = await message.reply_text(
            "🔄 Изменяю изображение...\n⏳ Скоро пришлю результат"
        )
        
        try:
            # Скачиваем новое фото-референс
            photo_file = await message.photo[-1].get_file()
            new_ref_path = f"{Config.TEMP_PHOTOS_DIR}/{user_id}_new_ref_{time.time()}.jpg"
            await photo_file.download_to_drive(new_ref_path)
            
            logger.info(f"📸 Новый референс скачан: {new_ref_path}")
            
            # Сохраняем текущее изображение как временный файл
            import tempfile
            current_image_path = None
            
            try:
                # Декодируем base64 изображение
                image_bytes = base64.b64decode(current_image_data)
                
                # Создаем временный файл для текущего изображения
                with tempfile.NamedTemporaryFile(delete=False, suffix='.jpg') as temp_file:
                    temp_file.write(image_bytes)
                    current_image_path = temp_file.name
                
                logger.info(f"💾 Сохранено текущее изображение: {current_image_path}")
                
                # Создаем естественный промпт для модификации с учетом нового фото
                modification_prompt = f"""TASK: Naturally modify the first image based on the description and inspiration from the second image.

CURRENT IMAGE: The first image shows the current scene that needs to be modified
REFERENCE PHOTO: The second image provides style inspiration and visual reference
MODIFICATION REQUEST: {modification_text}

INSTRUCTIONS:
1. Keep the same people, objects, and overall composition from the first image
2. Apply the requested modification: {modification_text}
3. Use the second image only as style/mood/lighting inspiration, NOT for copy-pasting elements
4. Make natural, realistic changes that flow with the original scene
5. Maintain visual consistency and natural lighting
6. The result should look like a natural evolution of the first image, not a collage

Create a harmonious, naturally modified version of the first image."""
                
                # Генерируем модифицированное изображение используя оба изображения как референсы
                result = await self.generate_image_from_reference([current_image_path, new_ref_path], modification_prompt)
                
                if result['success']:
                    result['generated_text'] = f"🔄 Изображение изменено с новым референсом: {modification_text}"
                    result['original_prompt'] = modification_text
                
                # Отправляем результат
                await self.send_generation_result(user_id, result, processing_message, context, update)
                
                logger.info(f"✅ Изображение изменено с новым референсом для пользователя {user_id}: {modification_text}")
                
            finally:
                # Удаляем временные файлы
                for temp_path in [current_image_path, new_ref_path]:
                    if temp_path and os.path.exists(temp_path):
                        os.remove(temp_path)
                        logger.info(f"🗑️ Временный файл удален: {temp_path}")
            
        except Exception as e:
            logger.error(f"❌ Ошибка при модификации с новым референсом: {e}")
            await processing_message.edit_text("❌ Произошла ошибка при изменении изображения. Попробуйте еще раз.")

    async def handle_media_group(self, update: Update, context: ContextTypes.DEFAULT_TYPE) -> None:
        """Обработчик альбомов фотографий для генерации"""
        message = update.message
        user_id = message.from_user.id
        media_group_id = message.media_group_id
        
        logger.info(f"📸 Получено фото из альбома от пользователя {user_id}, media_group_id: {media_group_id}")
        
        # Инициализируем альбом для пользователя, если его нет
        if not hasattr(self, 'user_albums'):
            self.user_albums = {}
        
        if user_id not in self.user_albums:
            self.user_albums[user_id] = {}
        
        if media_group_id not in self.user_albums[user_id]:
            self.user_albums[user_id][media_group_id] = {
                'photos': [],
                'caption': '',
                'timestamp': datetime.now(),
                'processed': False
            }
            logger.info(f"🆕 Создан новый альбом {media_group_id} для пользователя {user_id}")

        album = self.user_albums[user_id][media_group_id]
        
        # Добавляем фото в альбом
        if message.photo:
            photo_info = {
                'file_id': message.photo[-1].file_id,
                'file_unique_id': message.photo[-1].file_unique_id
            }
            album['photos'].append(photo_info)
            logger.info(f"📸 Добавлено фото в альбом: {photo_info['file_unique_id']}")
            
        # Сохраняем подпись
        if message.caption:
            album['caption'] = message.caption
            logger.info(f"📝 Сохранена подпись для альбома: {message.caption}")

        logger.info(f"📊 Текущее состояние альбома {media_group_id}: {len(album['photos'])} фото, обработан: {album['processed']}")

        # Планируем обработку альбома через небольшую задержку
        if not album['processed']:
            # Отменяем предыдущие задачи для этого альбома
            job_name = f"process_ref_album_{user_id}_{media_group_id}"
            current_jobs = context.job_queue.get_jobs_by_name(job_name)
            for job in current_jobs:
                job.schedule_removal()
                logger.info(f"🗑️ Отменена предыдущая задача обработки альбома")
            
            context.job_queue.run_once(
                self.process_reference_album,
                when=3,  # 3 секунды задержки
                data={'user_id': user_id, 'media_group_id': media_group_id},
                name=job_name
            )
            logger.info(f"⏰ Запланирована обработка альбома {media_group_id} через 3 секунды")

    async def process_reference_album(self, context: ContextTypes.DEFAULT_TYPE) -> None:
        """Обработка альбома референсных изображений"""
        job_data = context.job.data
        user_id = job_data['user_id']
        media_group_id = job_data['media_group_id']
        
        # Создаем фиктивный update объект для совместимости
        class FakeUpdate:
            def __init__(self, user_id):
                self.effective_user = type('User', (), {'id': user_id})()
        
        update = FakeUpdate(user_id)
        
        logger.info(f"🔄 Начинаем обработку альбома {media_group_id} для пользователя {user_id}")
        
        if user_id not in self.user_albums or media_group_id not in self.user_albums[user_id]:
            logger.warning(f"❌ Альбом {media_group_id} для пользователя {user_id} не найден")
            return

        album = self.user_albums[user_id][media_group_id]
        
        logger.info(f"📊 Состояние альбома: {len(album['photos'])} фото, подпись: '{album['caption']}', обработан: {album['processed']}")
        
        # Проверяем, что альбом еще не обработан
        if album['processed']:
            logger.info(f"⏭️ Альбом {media_group_id} уже обработан, пропускаем")
            return
            
        album['processed'] = True
        
        # Проверяем наличие подписи
        if not album['caption'].strip():
            await context.bot.send_message(
                chat_id=user_id,
                text="📝 Пожалуйста, добавьте подпись к альбому с описанием того, что вы хотите сгенерировать.\n\n🎨 **Пример:** Отправьте альбом с фотографиями и подписью \"красивый пейзаж в стиле импрессионизма\""
            )
            del self.user_albums[user_id][media_group_id]
            return

        # Отправляем сообщение о начале обработки
        processing_message = await context.bot.send_message(
            chat_id=user_id,
            text=f"🎨 Генерирую изображение...\n⏳ Скоро пришлю результат"
        )

        # Инициализируем список путей к фотографиям
        photo_paths = []
        
        try:
            # Скачиваем фотографии
            for i, photo_info in enumerate(album['photos']):
                file = await context.bot.get_file(photo_info['file_id'])
                file_path = f"{Config.TEMP_PHOTOS_DIR}/{user_id}_ref_{i}_{time.time()}.jpg"
                await file.download_to_drive(file_path)
                photo_paths.append(file_path)
                logger.info(f"📸 Референсное фото {i+1} скачано: {file_path}")

            # Генерируем изображение на основе референсов
            result = await self.generate_image_from_reference(photo_paths, album['caption'])
            
            # Проверяем результат
            if not result:
                logger.error("❌ Метод generate_image_from_reference вернул None")
                await processing_message.edit_text("❌ Произошла ошибка при генерации изображения. Попробуйте еще раз.")
                return
            
            # Логируем генерацию
            self.analytics.log_generation(user_id, 'album', album['caption'], result.get('success', False))
            
            # Отправляем результат
            await self.send_generation_result(user_id, result, processing_message, context, update)

        except Exception as e:
            logger.error(f"❌ Ошибка при обработке альбома referencer: {e}")
            await context.bot.send_message(
                chat_id=user_id,
                text="❌ Произошла ошибка при генерации изображения по референсам. Попробуйте еще раз."
            )
        finally:
            # Очищаем временные файлы
            for path in photo_paths:
                try:
                    os.remove(path)
                    logger.info(f"🗑️ Временный файл удален: {path}")
                except Exception as e:
                    logger.error(f"Ошибка удаления файла {path}: {e}")
            
            # Удаляем альбом из памяти
            if user_id in self.user_albums and media_group_id in self.user_albums[user_id]:
                del self.user_albums[user_id][media_group_id]

    async def generate_image_from_reference(self, photo_paths: List[str], prompt: str) -> Dict[str, Any]:
        """Генерация изображения на основе референсных фотографий"""
        try:
            logger.info(f"🎨 Генерация изображения по референсам: {prompt}")
            logger.info(f"📸 Количество референсных фото: {len(photo_paths)}")
            
            # Определяем тип операции по промпту
            is_modification = ("TASK: MODIFY" in prompt or "Modify the provided reference image" in prompt or "TASK: Naturally modify" in prompt)
            
            if is_modification:
                # Для модификации используем специальный промпт как есть
                enhanced_prompt = prompt
                logger.info("🔄 Режим модификации изображения - используем исходный промпт")
            else:
                # Создаем расширенный промпт для генерации на основе референсов
                enhanced_prompt = f"""Based on the provided reference images, create a new image with the following description: {prompt}

Use the visual style, colors, composition, and artistic elements from the reference images as inspiration, but create something new that matches the description: "{prompt}"

Key requirements:
- Maintain the visual style and aesthetic of the reference images
- Incorporate the color palette and artistic approach shown in the references
- Create a high-quality, detailed image
- Follow the specific description: {prompt}"""
                logger.info("🎨 Режим генерации по референсам - создаем новое изображение")

            # Используем прямой HTTP запрос к Gemini 2.5 Flash Image
            if self.gemini_session:
                # Подготавливаем данные для запроса с референсными изображениями
                parts = [{"text": enhanced_prompt}]
                
                # Добавляем референсные изображения
                for photo_path in photo_paths:
                    with open(photo_path, 'rb') as f:
                        image_data = f.read()
                        image_base64 = base64.b64encode(image_data).decode('utf-8')
                        parts.append({
                            "inline_data": {
                                "mime_type": "image/jpeg",
                                "data": image_base64
                            }
                        })
                
                request_data = {
                    "contents": [{"parts": parts}],
                    "generationConfig": {
                        "temperature": 0.8,
                        "maxOutputTokens": 4096
                    }
                }
                
                # Используем правильную модель для генерации изображений
                url = f"{self.gemini_base_url}/gemini-2.5-flash-image:generateContent?key={self.nano_banana_key}"
                response = self.gemini_session.post(url, json=request_data, timeout=120)
                
                if response.status_code == 200:
                    result = response.json()
                    logger.info("🔍 Полный ответ от Gemini Image API получен")
                    logger.debug(f"🔍 Полный ответ: {result}")
                    
                    if 'candidates' in result and result['candidates']:
                        candidate = result['candidates'][0]
                        logger.debug(f"🔍 Кандидат: {candidate}")
                        if 'content' in candidate and 'parts' in candidate['content']:
                            # Ищем изображение в ответе
                            for i, part in enumerate(candidate['content']['parts']):
                                logger.debug(f"🔍 Часть {i}: {part}")
                                if 'inlineData' in part and part['inlineData'].get('mimeType', '').startswith('image/'):
                                    image_data = part['inlineData'].get('data')
                                    if image_data:
                                        logger.info(f"✅ Изображение по референсам получено! Размер: {len(image_data)} символов base64")
                                        return {
                                            'success': True,
                                            'image_data': image_data,
                                            'generated_text': f"🎨 Изображение сгенерировано на основе {len(photo_paths)} фото по запросу:\n<b>«{prompt}»</b>",
                                            'original_prompt': prompt
                                        }
                                elif 'text' in part:
                                    logger.info(f"📝 Текстовый ответ: {part['text'][:100]}...")
                            
                            logger.warning("⚠️ Изображение не найдено в ответе API")
                            return {
                                'success': False,
                                'error': 'Не удалось сгенерировать изображение. Попробуйте еще раз и запросите немного иначе'
                            }
                    else:
                        logger.warning("⚠️ Нет кандидатов в ответе API")
                        return {
                            'success': False,
                            'error': 'API не вернул кандидатов для генерации'
                        }
                else:
                    logger.error(f"❌ Ошибка HTTP {response.status_code}: {response.text}")
                    return {
                        'success': False,
                        'error': f'HTTP {response.status_code}: {response.text}'
                    }
            else:
                return {
                    'success': False,
                    'error': 'HTTP клиент не настроен'
                }
                
        except Exception as e:
            logger.error(f"❌ Ошибка при генерации по референсам: {e}")
            return {
                'success': False,
                'error': str(e)
            }

    async def send_generation_result(self, chat_id: int, result: dict, processing_message, context, update=None):
        """Универсальный метод отправки результата генерации"""
        try:
            # Проверяем, что result не None и содержит нужные данные
            if not result:
                if processing_message:
                    await processing_message.edit_text("❌ Не удалось получить результат генерации.")
                else:
                    await context.bot.send_message(chat_id=chat_id, text="❌ Не удалось получить результат генерации.")
                return
                
            if result.get('success') and result.get('image_data'):
                # Отправляем изображение
                try:
                    image_bytes = base64.b64decode(result['image_data'])
                    image_file = io.BytesIO(image_bytes)
                    image_file.name = 'nano_banana_generated.jpg'
                    
                    # Создаем кнопку "Изменить"
                    keyboard = InlineKeyboardMarkup([
                        [InlineKeyboardButton("🔄 Изменить изображение", callback_data=f"modify_{chat_id}")]
                    ])
                    
                    sent_message = await context.bot.send_photo(
                            chat_id=chat_id,
                            photo=image_file,
                            caption=result.get('generated_text', ''),
                            reply_markup=keyboard,
                            parse_mode='HTML'
                        )
                    
                    # Сохраняем информацию о последней генерации
                    self.last_generations[chat_id] = {
                        'image_data': result['image_data'],
                        'original_prompt': result.get('original_prompt', ''),
                        'message_id': sent_message.message_id,
                        'timestamp': time.time()
                    }
                    
                    # Увеличиваем счетчик генераций при успешной отправке
                    if update:
                        self.increment_daily_limit(chat_id, context, update)
                    else:
                        # Для альбомов создаем фиктивный update
                        class FakeUpdate:
                            def __init__(self, user_id):
                                self.effective_user = type('User', (), {'id': user_id})()
                        fake_update = FakeUpdate(chat_id)
                        self.increment_daily_limit(chat_id, context, fake_update)
                    
                    # Удаляем сообщение о обработке (если оно существует)
                    if processing_message:
                        await processing_message.delete()
                    
                    logger.info(f"✅ Изображение отправлено пользователю {chat_id}")
                    
                except Exception as send_error:
                    logger.error(f"❌ Ошибка отправки изображения: {send_error}")
                    if processing_message:
                        await processing_message.edit_text(f"✅ Изображение сгенерировано, но произошла ошибка отправки: {send_error}")
                    else:
                        await context.bot.send_message(chat_id=chat_id, text=f"✅ Изображение сгенерировано, но произошла ошибка отправки: {send_error}")
                    
            else:
                # Ошибка генерации
                error_msg = result.get('error', 'Неизвестная ошибка') if result else 'Результат генерации пуст'
                if processing_message:
                    await processing_message.edit_text(f"❌ Не удалось сгенерировать изображение: {error_msg}")
                else:
                    await context.bot.send_message(chat_id=chat_id, text=f"❌ Не удалось сгенерировать изображение: {error_msg}")
                logger.error(f"❌ Ошибка генерации: {error_msg}")
                
        except Exception as e:
            logger.error(f"❌ Критическая ошибка в send_generation_result: {e}")
            try:
                if processing_message:
                    await processing_message.edit_text("❌ Произошла критическая ошибка при обработке результата.")
                else:
                    await context.bot.send_message(chat_id=chat_id, text="❌ Произошла критическая ошибка при обработке результата.")
            except:
                pass

    def extract_aspect_ratio(self, text):
        text_low = text.lower()
        aspect_ratio = None
        aspect_ratio_text = ""
        match = re.search(r'(?:размер|формат)?\s*([0-9]{1,2})\s*[\/: ]\s*([0-9]{1,2})', text_low)
        if match:
            w, h = match.groups()
            aspect_ratio = f"{w}:{h}"
            if (w == "16" and h == "9") or (w == "4" and h == "3"):
                aspect_ratio_text = f" wide horizontal image, landscape, {aspect_ratio} aspect ratio"
            elif (w == "9" and h == "16") or (w == "3" and h == "4"):
                aspect_ratio_text = f" vertical image, portrait, {aspect_ratio} aspect ratio"
            else:
                aspect_ratio_text = f" image in {aspect_ratio} aspect ratio"
        elif re.search(r'квадрат|1[\s:]{0,2}1', text_low):
            aspect_ratio = "1:1"
            aspect_ratio_text = " square image, 1:1 aspect ratio"
        elif re.search(r'вертикал|портрет|9[\s:]{0,2}16', text_low):
            aspect_ratio = "9:16"
            aspect_ratio_text = " vertical image, portrait, 9:16 aspect ratio"
        elif re.search(r'горизонтал|пейзаж|16[\s:]{0,2}9', text_low):
            aspect_ratio = "16:9"
            aspect_ratio_text = " wide horizontal image, landscape, 16:9 aspect ratio"
        return aspect_ratio, aspect_ratio_text

    def clean_format_words(self, text):
        filter_words = [
            r'(размер|формат)?\s*[0-9]{1,2}\s*[\/: ]\s*[0-9]{1,2}',
            r'квадрат(ная|ный|ное)?', r'портрет', r'вертикаль(ная|ный|ное)?', r'горизонтал(ьная|ьный|ьное)?', r'пейзаж(ная|ный|ное)?', r'1[\s:]{0,2}1', r'9[\s:]{0,2}16', r'16[\s:]{0,2}9'
        ]
        for w in filter_words:
            text = re.sub(w, '', text, flags=re.IGNORECASE).strip()
        text = re.sub(r'\s{2,}', ' ', text)
        return text

    def get_generation_strategy(self, text: str):
        aspect_ratio, aspect_ratio_text = self.extract_aspect_ratio(text)
        clean_text = self.clean_format_words(text)
        file_mode = False
        if not aspect_ratio or aspect_ratio == "1:1":
            aspect_ratio = "1:1"
            aspect_ratio_text = " square image, 1:1 aspect ratio"
            file_mode = False
        else:
            file_mode = True
        prompt = clean_text + aspect_ratio_text
        logger.info(f"[GENERATION_STRATEGY] text='{text}' aspect_ratio={aspect_ratio} mode={'file' if file_mode else 'photo'} prompt='{prompt}'")
        return prompt, file_mode, clean_text

    def run(self):
        """Запуск бота"""
        try:
            # Создаем приложение с дополнительными настройками
            application = Application.builder().token(self.bot_token).build()
            
            # Добавляем обработчики
            application.add_handler(CommandHandler("start", self.start_command))
            application.add_handler(CommandHandler("analytics", self.analytics_command))
            application.add_handler(CommandHandler("broadcast", self.broadcast_command))
            application.add_handler(MessageHandler(filters.TEXT & ~filters.COMMAND, self.handle_text_message))
            # Обработчик для голосовых сообщений
            application.add_handler(MessageHandler(filters.VOICE, self.handle_voice_message))
            # Обработчик для альбомов (фотографии с media_group_id)
            application.add_handler(MessageHandler(filters.PHOTO & filters.UpdateType.MESSAGE, self.handle_photo_with_album_check))
            application.add_handler(CallbackQueryHandler(self.handle_button_callback))
            
            logger.info("🚀 Запуск Nano Banana бота с генерацией изображений...")
            
            # Простой запуск без retry цикла
            application.run_polling(
                drop_pending_updates=True,
                allowed_updates=["message", "callback_query"],
                timeout=30,
                bootstrap_retries=3
            )
            
        except Exception as e:
            logger.error(f"❌ Ошибка при запуске бота: {e}")
            raise

def main():
    """Главная функция запуска бота"""
    try:
        bot = NanoBananaBot()
        bot.run()
    except KeyboardInterrupt:
        logger.info("👋 Бот остановлен пользователем")
    except Exception as e:
        logger.error(f"💥 Критическая ошибка: {e}")
        raise

if __name__ == "__main__":
    main()