import asyncio
import json
import os
import urllib.parse
from datetime import datetime
from aiogram import Bot, Dispatcher, types, F
from aiogram.filters import Command
from aiogram.utils.keyboard import ReplyKeyboardBuilder, InlineKeyboardBuilder
from flask import Flask, request, jsonify, render_template_string, redirect
import logging
import threading
from huggingface_hub import HfApi, hf_hub_download
from huggingface_hub.utils import RepositoryNotFoundError
from werkzeug.utils import secure_filename

# Настройка логирования
logging.basicConfig(level=logging.INFO)
logger = logging.getLogger(__name__)

# Инициализация бота и Flask
BOT_TOKEN = '7595736142:AAHSU3WGItBkebIgjO293J2WjX5qWAne8Y8'
bot = Bot(token=BOT_TOKEN)
dp = Dispatcher()
app = Flask(__name__)

# Путь для хранения данных
DATA_FILE = 'data2.json'

# Настройки Hugging Face
REPO_ID = "flpolprojects/Clients"
HF_TOKEN_WRITE = os.getenv("HF_TOKEN")
HF_TOKEN_READ = os.getenv("HF_TOKEN_READ")

# Функции для работы с данными
def load_data():
    try:
        download_db_from_hf()
        with open(DATA_FILE, 'r', encoding='utf-8') as f:
            loaded_data = json.load(f)
        if not (isinstance(loaded_data, dict) and 'products' in loaded_data and 'orders' in loaded_data):
            logger.error("Неверная структура JSON файла")
            loaded_data = {'products': [], 'orders': []}
        if "categories" not in loaded_data:
            loaded_data["categories"] = []
        return loaded_data
    except Exception as e:
        logger.error(f"Ошибка при загрузке данных: {e}")
        return {'products': [], 'orders': [], 'categories': []}

def save_data(data):
    try:
        with open(DATA_FILE, 'w', encoding='utf-8') as f:
            json.dump(data, f, ensure_ascii=False, indent=4)
        # upload_db_to_hf() убрано отсюда
    except Exception as e:
        logger.error(f"Ошибка при сохранении данных: {e}")

def upload_db_to_hf():
    try:
        api = HfApi()
        api.upload_file(
            path_or_fileobj=DATA_FILE,
            path_in_repo=DATA_FILE,
            repo_id=REPO_ID,
            repo_type="dataset",
            token=HF_TOKEN_WRITE,
            commit_message=f"Автоматическое резервное копирование {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}"
        )
        logger.info("База загружена на Hugging Face")
    except Exception as e:
        logger.error(f"Ошибка при загрузке резервной копии: {e}")

def download_db_from_hf():
    try:
        hf_hub_download(
            repo_id=REPO_ID,
            filename=DATA_FILE,
            repo_type="dataset",
            token=HF_TOKEN_READ,
            local_dir=".",
            local_dir_use_symlinks=False
        )
        logger.info("База скачана из Hugging Face")
    except Exception as e:
        logger.error(f"Ошибка при скачивании: {e}")
        raise

# Периодическое копирование каждые 30 секунд
def start_periodic_backup():
    def backup_loop():
        upload_db_to_hf()
        # Запускаем следующий вызов через 30 секунд
        threading.Timer(30, backup_loop).start()

    # Запускаем первый вызов
    threading.Timer(30, backup_loop).start()
    logger.info("Периодическое копирование каждые 30 секунд запущено")

# Загрузка данных
data = load_data()

# Формирование клавиатур
def get_main_keyboard():
    builder = ReplyKeyboardBuilder()
    builder.button(text="📋 Каталог")
    builder.button(text="🛒 Корзина")
    builder.button(text="📦 Заказы")
    builder.adjust(2)
    return builder.as_markup(resize_keyboard=True)

def get_category_keyboard():
    builder = InlineKeyboardBuilder()
    for category in data['categories']:
        builder.button(text=category['name'], callback_data=f"cat_{category['id']}")
    builder.adjust(2)
    return builder.as_markup()

def get_product_keyboard(product_id):
    builder = InlineKeyboardBuilder()
    builder.button(text="Добавить в корзину", callback_data=f"add_{product_id}")
    return builder.as_markup()

# Обработчики бота
@dp.message(Command("start"))
async def cmd_start(message: types.Message):
    await message.answer("Здравствуйте ! это магазин Routine!. Выберите действие:", reply_markup=get_main_keyboard())

# Изменено условие на "📋 Каталог", чтобы соответствовать кнопке
@dp.message(F.text == "📋 Каталог")
async def show_categories(message: types.Message):
    if not data['categories']:
        await message.answer("Нет доступных категорий.")
        return
    await message.answer("Выберите категорию:", reply_markup=get_category_keyboard())

@dp.callback_query(F.data.startswith("cat_"))
async def show_products_in_category(callback_query: types.CallbackQuery):
    try:
        cat_id = int(callback_query.data.split('_')[1])
        products_in_cat = [p for p in data['products'] if p.get('category_id') == cat_id]
        
        if not products_in_cat:
            await bot.send_message(callback_query.from_user.id, "В этой категории нет товаров.")
            await bot.answer_callback_query(callback_query.id)
            return

        async def send_product_batch(products_batch):
            for product in products_batch:
                photo_url = f"https://huggingface.co/datasets/{REPO_ID}/resolve/main/photos/{product['photo']}" if product.get('photo') else None
                caption = f"🏷 {product['name']} - {product['price']} сом\nОписание: {product['description']}\n/id: {product['id']}"
                try:
                    if photo_url:
                        await bot.send_photo(chat_id=callback_query.from_user.id, photo=photo_url, caption=caption, reply_markup=get_product_keyboard(product['id']))
                    else:
                        await bot.send_message(callback_query.from_user.id, caption, reply_markup=get_product_keyboard(product['id']))
                except Exception as e:
                    logger.error(f"Ошибка при отправке: {e}")
                    await bot.send_message(callback_query.from_user.id, caption, reply_markup=get_product_keyboard(product['id']))

        batch_size = 5
        for i in range(0, len(products_in_cat), batch_size):
            batch = products_in_cat[i:i + batch_size]
            await send_product_batch(batch)
            await asyncio.sleep(0.1)
            
        await bot.answer_callback_query(callback_query.id)
    except Exception as e:
        logger.error(f"Ошибка в show_products_in_category: {e}")
        await bot.answer_callback_query(callback_query.id, "Ошибка при загрузке товаров")

@dp.message(F.text == "🛒 Корзина")
async def show_cart(message: types.Message):
    user_id = message.from_user.id
    cart = next((o for o in data['orders'] if o['user_id'] == user_id and not o.get('completed')), None)
    if not cart or not cart['items']:
        await message.answer("Ваша корзина пуста.")
        return
    total = 0
    response = "Ваша корзина:\n"
    for item in cart['items']:
        product = next(p for p in data['products'] if p['id'] == item['product_id'])
        response += f"🏷 {product['name']} - {product['price']} сом x {item['quantity']}\n"
        total += product['price'] * item['quantity']
    response += f"\nИтого: {total} сом"
    builder = InlineKeyboardBuilder()
    builder.button(text="Оформить заказ", callback_data=f"complete_{user_id}")
    await message.answer(response, reply_markup=builder.as_markup())

@dp.callback_query(F.data.startswith("add_"))
async def add_to_cart(callback_query: types.CallbackQuery):
    try:
        product_id = int(callback_query.data.split('_')[1])
        product = next((p for p in data['products'] if p['id'] == product_id), None)
        if product:
            user_id = callback_query.from_user.id
            cart = next((o for o in data['orders'] if o['user_id'] == user_id and not o.get('completed')), None)
            if not cart:
                cart = {'user_id': user_id, 'items': [], 'date': datetime.now().isoformat()}
                data['orders'].append(cart)
            cart['items'].append({'product_id': product_id, 'quantity': 1})
            save_data(data)
            await bot.answer_callback_query(callback_query.id, "Товар добавлен в корзину!")
    except Exception as e:
        logger.error(f"Ошибка при добавлении в корзину: {e}")
        await bot.answer_callback_query(callback_query.id, "Ошибка")

@dp.callback_query(F.data.startswith("complete_"))
async def complete_order(callback_query: types.CallbackQuery):
    try:
        user_id = int(callback_query.data.split('_')[1])
        cart = next((o for o in data['orders'] if o['user_id'] == user_id and not o.get('completed')), None)
        if cart and cart['items']:
            total = 0
            cart_text = "Привет, я хочу сделать заказ:\n"
            for item in cart['items']:
                product = next((p for p in data['products'] if p['id'] == item['product_id']), None)
                if product:
                    cart_text += f"{product['name']} - {product['price']} сом x {item['quantity']}\n"
                    total += product['price'] * item['quantity']
            cart_text += f"\nИтого: {total} сом"
            encoded_text = urllib.parse.quote(cart_text)
            whatsapp_link = f"https://wa.me/996709513331?text={encoded_text}"
            data['orders'].remove(cart)
            save_data(data)
            await bot.send_message(user_id, f"Оформите заказ через WhatsApp:\n{whatsapp_link}")
            await bot.answer_callback_query(callback_query.id)
    except Exception as e:
        logger.error(f"Ошибка при оформлении заказа: {e}")
        await bot.answer_callback_query(callback_query.id, "Ошибка")

@dp.message(F.text == "📦 Заказы")
async def show_orders(message: types.Message):
    user_id = message.from_user.id
    user_orders = [o for o in data['orders'] if o.get('completed')]
    if not user_orders:
        await message.answer("У вас нет оформленных заказов.")
        return
    for order in user_orders:
        response = "Ваш заказ:\n"
        total = 0
        for item in order['items']:
            product = next(p for p in data['products'] if p['id'] == item['product_id'])
            response += f"🏷 {product['name']} - {product['price']} сом x {item['quantity']}\n"
            total += product['price'] * item['quantity']
        response += f"\nИтого: {total} сом\nДата: {order['date']}"
        await message.answer(response)

# Админ-панель
admin_html = """
<!DOCTYPE html>
<html>
<head>
    <title>Админ-панель</title>
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <style>
        body {
            font-family: Arial, sans-serif;
            margin: 10px;
            background-color: #f0f0f0;
        }
        .container {
            max-width: 1000px;
            margin: 0 auto;
        }
        .section {
            background-color: #fff;
            padding: 10px;
            margin-bottom: 15px;
            border-radius: 5px;
        }
        h1, h2, h3 {
            margin: 10px 0;
        }
        input, textarea, select {
            width: 100%;
            margin: 5px 0;
            padding: 8px;
            box-sizing: border-box;
        }
        button {
            background-color: #4CAF50;
            color: white;
            padding: 8px 12px;
            border: none;
            border-radius: 5px;
            cursor: pointer;
            width: 100%;
            margin: 5px 0;
        }
        button:hover {
            background-color: #45a049;
        }
        img {
            max-width: 100%;
            height: auto;
            max-height: 150px;
        }
        .item {
            border: 1px solid #ccc;
            padding: 10px;
            margin: 5px 0;
            word-wrap: break-word;
        }
        @media (max-width: 600px) {
            .section {
                padding: 8px;
            }
            button {
                padding: 6px 10px;
            }
            h1 {
                font-size: 1.5em;
            }
            h2 {
                font-size: 1.2em;
            }
            h3 {
                font-size: 1em;
            }
        }
    </style>
</head>
<body>
    <div class="container">
        <h1>Админ-панель</h1>
        <div class="section">
            <h2>Управление категориями</h2>
            <form id="addCategoryForm" method="POST" action="/add_category">
                <input type="text" name="name" placeholder="Название категории" required>
                <button type="submit">Добавить категорию</button>
            </form>
            <h3>Существующие категории</h3>
            {% if categories %}
                {% for category in categories %}
                <div class="item">
                    {{ category.name }} (ID: {{ category.id }})
                    <button onclick="deleteCategory({{ category.id }})">Удалить</button>
                </div>
                {% endfor %}
            {% else %}
                <p>Нет категорий.</p>
            {% endif %}
        </div>
        <div class="section">
            <h2>Управление товарами</h2>
            <form id="addProductForm" method="POST" enctype="multipart/form-data" action="/add_product">
                <input type="text" name="name" placeholder="Название" required>
                <input type="number" name="price" placeholder="Цена" step="0.01" required>
                <textarea name="description" placeholder="Описание" required></textarea>
                <label>Категория:</label>
                <select name="category_id" required>
                    <option value="">Выберите категорию</option>
                    {% for category in categories %}
                    <option value="{{ category.id }}">{{ category.name }}</option>
                    {% endfor %}
                </select>
                <input type="file" name="photo" accept="image/*">
                <button type="submit">Добавить товар</button>
            </form>
            <h3>Существующие товары</h3>
            {% if products %}
                {% for product in products %}
                <div class="item">
                    {{ product.name }} - {{ product.price }} сом<br>
                    {{ product.description }}<br>
                    {% if product.photo %}
                        <img src="https://huggingface.co/datasets/{{ repo_id }}/resolve/main/photos/{{ product.photo }}" alt="{{ product.name }}">
                    {% endif %}
                    <button onclick="deleteProduct({{ product.id }})">Удалить</button>
                </div>
                {% endfor %}
            {% else %}
                <p>Нет товаров.</p>
            {% endif %}
        </div>
        <div class="section">
            <h2>Заказы</h2>
            {% if orders %}
                {% for order in orders %}
                <div class="item">
                    Пользователь: {{ order.user_id }}<br>
                    Дата: {{ order.date }}<br>
                    Товары:
                    {% for item in order['items'] %}
                        {% for product in products %}
                            {% if product.id == item.product_id %}
                                {{ item.quantity }} x {{ product.name }}<br>
                            {% endif %}
                        {% endfor %}
                    {% endfor %}
                </div>
                {% endfor %}
            {% else %}
                <p>Нет заказов.</p>
            {% endif %}
        </div>
    </div>
    <script>
        const eventSource = new EventSource('/updates');
        eventSource.onmessage = function(event) {
            if (event.data === 'update') {
                window.location.reload();
            }
        };
        eventSource.onerror = function() {
            console.log("Ошибка SSE, reconnecting...");
        };

        async function deleteProduct(productId) {
            const response = await fetch(`/delete_product/${productId}`, { method: 'POST' });
            if (response.ok) broadcastUpdate();
        }
        async function deleteCategory(categoryId) {
            const response = await fetch(`/delete_category/${categoryId}`, { method: 'POST' });
            if (response.ok) broadcastUpdate();
        }
        function broadcastUpdate() {
            fetch('/broadcast_update', { method: 'POST' });
        }
    </script>
</body>
</html>
"""

update_event = threading.Event()

@app.route('/')
def admin_panel():
    try:
        return render_template_string(admin_html, products=data['products'], orders=data['orders'], categories=data['categories'], repo_id=REPO_ID)
    except Exception as e:
        logger.error(f"Ошибка в шаблоне: {e}")
        return "Ошибка сервера", 500

@app.route('/add_product', methods=['POST'])
def add_product():
    try:
        name = request.form['name']
        price = float(request.form['price'])
        description = request.form['description']
        category_id = int(request.form['category_id'])
        photo = request.files.get('photo')
        product_id = max((p['id'] for p in data['products']), default=0) + 1

        photo_filename = None
        if photo and photo.filename:
            photo_filename = secure_filename(photo.filename)
            temp_path = os.path.join(".", photo_filename)
            photo.save(temp_path)
            api = HfApi()
            api.upload_file(
                path_or_fileobj=temp_path,
                path_in_repo=f"photos/{photo_filename}",
                repo_id=REPO_ID,
                repo_type="dataset",
                token=HF_TOKEN_WRITE,
                commit_message=f"Добавлено фото для товара {name}"
            )
            os.remove(temp_path)

        data['products'].append({
            'id': product_id,
            'name': name,
            'price': price,
            'description': description,
            'category_id': category_id,
            'photo': photo_filename
        })
        save_data(data)
        update_event.set()
        return redirect("/")
    except Exception as e:
        logger.error(f"Ошибка при добавлении товара: {e}")
        return jsonify({'status': 'error', 'message': str(e)}), 500

@app.route('/delete_product/<int:product_id>', methods=['POST'])
def delete_product(product_id):
    try:
        data['products'] = [p for p in data['products'] if p['id'] != product_id]
        save_data(data)
        update_event.set()
        return jsonify({'status': 'success'})
    except Exception as e:
        logger.error(f"Ошибка при удалении товара: {e}")
        return jsonify({'status': 'error', 'message': str(e)}), 500

@app.route('/add_category', methods=['POST'])
def add_category():
    try:
        name = request.form['name']
        category_id = max((c['id'] for c in data['categories']), default=0) + 1
        data['categories'].append({'id': category_id, 'name': name})
        save_data(data)
        update_event.set()
        return redirect("/")
    except Exception as e:
        logger.error(f"Ошибка при добавлении категории: {e}")
        return jsonify({'status': 'error', 'message': str(e)}), 500

@app.route('/delete_category/<int:category_id>', methods=['POST'])
def delete_category(category_id):
    try:
        data['categories'] = [c for c in data['categories'] if c['id'] != category_id]
        save_data(data)
        update_event.set()
        return jsonify({'status': 'success'})
    except Exception as e:
        logger.error(f"Ошибка при удалении категории: {e}")
        return jsonify({'status': 'error', 'message': str(e)}), 500

@app.route('/updates')
def sse_updates():
    def stream():
        while True:
            update_event.wait()
            yield "data: update\n\n"
            update_event.clear()
    return app.response_class(stream(), mimetype="text/event-stream")

@app.route('/broadcast_update', methods=['POST'])
def broadcast_update():
    update_event.set()
    return jsonify({'status': 'success'})

# Запуск
async def on_startup(_):
    logger.info("Бот запущен!")

def run_flask():
    app.run(host='0.0.0.0', port=7860, debug=True, use_reloader=False)

if __name__ == '__main__':
    flask_thread = threading.Thread(target=run_flask, daemon=True)
    flask_thread.start()
    logger.info("Flask запущен")
    
    # Запуск периодического копирования
    start_periodic_backup()

    try:
        asyncio.run(dp.start_polling(bot, on_startup=on_startup))
    except KeyboardInterrupt:
        logger.info("Остановка")
    finally:
        flask_thread.join()