# handlers/qr_code.py
from aiogram import Router, F
from aiogram.filters import StateFilter
from aiogram.fsm.context import FSMContext
from aiogram.fsm.state import State, StatesGroup
from aiogram.types import Message, InlineKeyboardMarkup, InlineKeyboardButton
import logging
from PIL import Image
from pyzbar.pyzbar import decode
import io
import base64
import traceback # Для полного стека ошибок
import random
from datetime import datetime
import re # Для парсинга URL
import os
import time
import json
# Импорты для БД
from db import get_user_balance, update_user_balance, save_payment
# Настройка логирования в файл log.txt
logging.basicConfig(filename='log.txt', level=logging.INFO, format='%(asctime)s - %(levelname)s - %(message)s')
# Импорт клавиатуры
from keyboard import get_main_menu_keyboard
router = Router()
class QrCodeStates(StatesGroup):
    wait_qr = State()
def get_chat_id(key: str):
    """Загрузка chat_id из chats.json"""
    try:
        with open(os.path.join(os.path.dirname(os.path.dirname(__file__)), 'chats.json'), 'r', encoding='utf-8') as f:
            data = json.load(f)
        return data.get(key)
    except Exception as e:
        logging.error(f"Ошибка загрузки chats.json: {str(e)}")
        return None
def get_function_status(key: str):
    """Загрузка статуса функции из function.json"""
    try:
        with open(os.path.join(os.path.dirname(os.path.dirname(__file__)), 'function.json'), 'r', encoding='utf-8') as f:
            data = json.load(f)
        return data.get(key, True)
    except Exception as e:
        logging.error(f"Ошибка загрузки function.json: {str(e)}")
        return True
def get_procent_rate():
    """Загрузка процента комиссии из procent.json"""
    try:
        with open(os.path.join(os.path.dirname(os.path.dirname(__file__)), 'procent.json'), 'r', encoding='utf-8') as f:
            data = json.load(f)
        return data.get('procent', 10) / 100  # Возвращаем как десятичную дробь
    except Exception as e:
        logging.error(f"Ошибка загрузки procent.json: {str(e)}")
        return 0.1  # Дефолт 10%
@router.message(F.text == "📷 QrCode")
async def qr_code_start(message: Message, state: FSMContext):
    if not get_function_status('qrcode'):
        await message.answer("Проводятся технические работы")
        return
    await message.answer("Отправьте Фото или файл с QR-кодом:")
    await state.set_state(QrCodeStates.wait_qr)
@router.message(StateFilter(QrCodeStates.wait_qr), F.photo)
async def process_qr_photo(message: Message, state: FSMContext):
    try:
        # Скачиваем фото
        photo = message.photo[-1]
        file = await message.bot.get_file(photo.file_id)
        file_bytes = await message.bot.download_file(file.file_path)
     
        # Логируем размер файла для отладки
        file_value = file_bytes.getvalue()
        logging.info(f"Получено фото: размер {len(file_value)} байт, file_id {photo.file_id}")
     
        # Открываем изображение
        image = Image.open(io.BytesIO(file_value))
     
        # Читаем QR-код
        decoded_objects = decode(image)
        logging.info(f"Найдено QR-кодов: {len(decoded_objects)}")
     
        if not decoded_objects:
            await message.answer("❌ QR-код не найден на изображении. Отправьте четкое фото с QR-кодом.")
            # Сохраняем base64 для анализа
            img_base64 = base64.b64encode(file_value).decode('utf-8')
            logging.warning(f"QR не найден. Base64 изображения: {img_base64[:200]}...") # Первые 200 символов
            return
     
        # Получаем содержимое QR (ссылка)
        qr_data = decoded_objects[0].data.decode('utf-8')
        logging.info(f"QR data: {qr_data}")
     
        # Парсинг URL для sum и cur
        match = re.search(r'sum=(\d+)&cur=([A-Z]+)', qr_data)
        if not match or match.group(2) != 'RUB':
            await message.answer("Ваша Qr Code не верный\nобратитесь в тех поддержку либо попробуйте использовать другой метод оплаты")
            await state.clear()
            return
     
        sum_value = int(match.group(1))
        cur = match.group(2)
     
        # Убираем последние два нуля
        amount = sum_value // 100
        logging.info(f"Извлечено: сумма {amount} RUB из {sum_value}")
     
        # Получаем актуальный процент комиссии
        procent_rate = get_procent_rate()
        commission = amount * procent_rate
        total_needed = amount + commission
     
        # Проверка баланса
        user_id = message.from_user.id
        balance = get_user_balance(user_id)
     
        if balance < total_needed:
            keyboard = InlineKeyboardMarkup(inline_keyboard=[
                [InlineKeyboardButton(text="💰 Пополнить баланс", callback_data="top_up_balance")],
                [InlineKeyboardButton(text="🔙 Назад", callback_data="back_to_menu")]
            ])
            await message.answer(f"❌ На вашем балансе недостаточно средств. Требуется {total_needed:.2f} рублей (сумма {amount} + комиссия {commission:.2f}).", reply_markup=keyboard)
            await state.clear()
            return
     
        # Создаём папку upload, если нет
        upload_dir = 'upload'
        if not os.path.exists(upload_dir):
            os.makedirs(upload_dir)
     
        # Сохраняем файл
        timestamp = int(time.time())
        filename = f'qr_{user_id}_{timestamp}.jpg'
        file_path = os.path.join(upload_dir, filename)
        with open(file_path, 'wb') as f:
            f.write(file_value)
        qr_code_path = file_path # Путь для БД
     
        # Генерация ID заявки и datetime
        date_time = datetime.now().strftime('%Y-%m-%d %H:%M:%S')
        id_zayavka = random.randint(100000, 999999)
        phone = '' # Для QR нет номера
     
        # Сначала сохраняем заявку в БД
        success = save_payment(user_id, id_zayavka, "load", date_time, phone, amount, qr_code=qr_code_path, link=qr_data)
        if not success:
            await message.answer("❌ Ошибка при создании заявки. Деньги не списаны.")
            await state.clear()
            return
     
        # Если заявка сохранена успешно, списываем деньги
        update_user_balance(user_id, -total_needed)
     
        # Уведомление в Telegram
        try:
            zayavki_chat_id = get_chat_id("zayavki")
            if zayavki_chat_id:
                notification_text = f"Новая заявка QR\nUser ID: {user_id}\nID заявки: {id_zayavka}\nQR Code: {qr_code_path}\nLink: {qr_data}\nSumma: {amount}\nDate: {date_time}"
                await message.bot.send_message(chat_id=zayavki_chat_id, text=notification_text)
            else:
                logging.error("Не удалось получить chat_id для zayavki")
        except Exception as e:
            logging.error(f"Ошибка отправки уведомления QR: {str(e)}")
     
        await message.answer(
            f"✅ Оплата через QR подтверждена!\n"
            f"Сумма: {amount} рублей ({commission:.2f} комиссия, итого {total_needed:.2f})\n"
            f"Новый баланс: {get_user_balance(user_id):.2f} рублей."
        )
     
        # Возврат в главное меню
        keyboard = get_main_menu_keyboard()
        await message.answer("Операция завершена. Главное меню:", reply_markup=keyboard)
     
        await state.clear()
     
    except Exception as e:
        error_msg = f"Ошибка чтения QR из фото: {str(e)}\nTraceback: {traceback.format_exc()}"
        logging.error(error_msg)
        print(error_msg) # В консоль для немедленной отладки
        await message.answer("❌ Ошибка при чтении QR-кода. Проверьте log.txt на детали.")
        await state.clear()
@router.message(StateFilter(QrCodeStates.wait_qr), F.document)
async def process_qr_document(message: Message, state: FSMContext):
    try:
        # Скачиваем файл
        document = message.document
        if not document.mime_type.startswith('image/'):
            await message.answer("❌ Отправьте изображение (фото или файл PNG/JPG).")
            return
     
        file = await message.bot.get_file(document.file_id)
        file_bytes = await message.bot.download_file(file.file_path)
     
        # Логируем размер файла
        file_value = file_bytes.getvalue()
        logging.info(f"Получен файл: {document.file_name}, размер {len(file_value)} байт")
     
        # Открываем изображение
        image = Image.open(io.BytesIO(file_value))
     
        # Читаем QR-код
        decoded_objects = decode(image)
        logging.info(f"Найдено QR-кодов в файле: {len(decoded_objects)}")
     
        if not decoded_objects:
            await message.answer("❌ QR-код не найден в файле. Отправьте четкое изображение с QR-кодом.")
            # Сохраняем base64
            img_base64 = base64.b64encode(file_value).decode('utf-8')
            logging.warning(f"QR не найден в файле. Base64: {img_base64[:200]}...")
            return
     
        # Получаем содержимое QR (ссылка)
        qr_data = decoded_objects[0].data.decode('utf-8')
        logging.info(f"QR data из файла: {qr_data}")
     
        # Парсинг URL для sum и cur (аналогично фото)
        match = re.search(r'sum=(\d+)&cur=([A-Z]+)', qr_data)
        if not match or match.group(2) != 'RUB':
            await message.answer("Ваша Qr Code не верный\nобратитесь в тех поддержку либо попробуйте использовать другой метод оплаты")
            await state.clear()
            return
     
        sum_value = int(match.group(1))
        cur = match.group(2)
     
        # Убираем последние два нуля
        amount = sum_value // 100
        logging.info(f"Извлечено: сумма {amount} RUB из {sum_value}")
     
        # Получаем актуальный процент комиссии
        procent_rate = get_procent_rate()
        commission = amount * procent_rate
        total_needed = amount + commission
     
        # Проверка баланса
        user_id = message.from_user.id
        balance = get_user_balance(user_id)
     
        if balance < total_needed:
            keyboard = InlineKeyboardMarkup(inline_keyboard=[
                [InlineKeyboardButton(text="💰 Пополнить баланс", callback_data="top_up_balance")],
                [InlineKeyboardButton(text="🔙 Назад", callback_data="back_to_menu")]
            ])
            await message.answer(f"❌ На вашем балансе недостаточно средств. Требуется {total_needed:.2f} рублей (сумма {amount} + комиссия {commission:.2f}).", reply_markup=keyboard)
            await state.clear()
            return
     
        # Создаём папку upload, если нет
        upload_dir = 'upload'
        if not os.path.exists(upload_dir):
            os.makedirs(upload_dir)
     
        # Сохраняем файл
        timestamp = int(time.time())
        filename = f'qr_{user_id}_{timestamp}.jpg'
        file_path = os.path.join(upload_dir, filename)
        with open(file_path, 'wb') as f:
            f.write(file_value)
        qr_code_path = file_path # Путь для БД
     
        # Генерация ID заявки и datetime
        date_time = datetime.now().strftime('%Y-%m-%d %H:%M:%S')
        id_zayavka = random.randint(100000, 999999)
        phone = '' # Для QR нет номера
     
        # Сначала сохраняем заявку в БД
        success = save_payment(user_id, id_zayavka, "load", date_time, phone, amount, qr_code=qr_code_path, link=qr_data)
        if not success:
            await message.answer("❌ Ошибка при создании заявки. Деньги не списаны.")
            await state.clear()
            return
     
        # Если заявка сохранена успешно, списываем деньги
        update_user_balance(user_id, -total_needed)
     
        # Уведомление в Telegram
        try:
            zayavki_chat_id = get_chat_id("zayavki")
            if zayavki_chat_id:
                notification_text = f"Новая заявка QR\nUser ID: {user_id}\nID заявки: {id_zayavka}\nQR Code: {qr_code_path}\nLink: {qr_data}\nSumma: {amount}\nDate: {date_time}"
                await message.bot.send_message(chat_id=zayavki_chat_id, text=notification_text)
            else:
                logging.error("Не удалось получить chat_id для zayavki")
        except Exception as e:
            logging.error(f"Ошибка отправки уведомления QR: {str(e)}")
     
        await message.answer(
            f"✅ Оплата через QR подтверждена!\n"
            f"Сумма: {amount} рублей ({commission:.2f} комиссия, итого {total_needed:.2f})\n"
            f"Новый баланс: {get_user_balance(user_id):.2f} рублей."
        )
     
        # Возврат в главное меню
        keyboard = get_main_menu_keyboard()
        await message.answer("Операция завершена. Главное меню:", reply_markup=keyboard)
     
        await state.clear()
     
    except Exception as e:
        error_msg = f"Ошибка чтения QR из файла: {str(e)}\nTraceback: {traceback.format_exc()}"
        logging.error(error_msg)
        print(error_msg) # В консоль
        await message.answer("❌ Ошибка при чтении QR-кода из файла. Проверьте log.txt.")
        await state.clear()