import logging
from aiogram import Bot, Dispatcher, types
from aiogram.contrib.middlewares.logging import LoggingMiddleware
from aiogram.types import ParseMode, ReplyKeyboardMarkup, KeyboardButton
from aiogram.types import InlineKeyboardMarkup, InlineKeyboardButton
from aiogram.utils import executor
import sqlite3
from aiogram.dispatcher import FSMContext
from aiogram.dispatcher.filters.state import State, StatesGroup
from aiogram.contrib.fsm_storage.memory import MemoryStorage
from aiogram.utils.exceptions import MessageNotModified
import datetime
from datetime import datetime, date, timedelta
import uuid
import asyncio
from aiohttp import web
import matplotlib.dates as mdates
from collections import defaultdict
import aiofiles
import numpy as np
import matplotlib.pyplot as plt
import mplcyberpunk
import tempfile
import os
from openai import OpenAI
from PIL import Image, ImageDraw, ImageFont
import calendar
from apscheduler.schedulers.asyncio import AsyncIOScheduler
from urllib import parse
from urllib.parse import urlparse
import tempfile
import math

# Отключаем логирование APScheduler
logging.getLogger('apscheduler').setLevel(logging.WARNING)
logging.getLogger('apscheduler.scheduler').propagate = False
scheduler = AsyncIOScheduler()

TOKEN = '7107660781:AAGhWrPUYYZXi3AMDx-25jF8qWg96uRJE9U'
WEB_SERVER_HOST = "127.0.0.1"
WEB_SERVER_PORT = 8443
WEBHOOK_PATH = "/webhook"
WEBHOOK_SECRET = "toptopsecret"
BASE_WEBHOOK_URL = "https://bbfiles.ru"

API_TOKEN = '7107660781:AAGhWrPUYYZXi3AMDx-25jF8qWg96uRJE9U'

# Инициализация бота и диспетчера
bot = Bot(token=TOKEN, parse_mode=ParseMode.HTML)
storage = MemoryStorage()
dp = Dispatcher(bot, storage=storage)
dp.middleware.setup(LoggingMiddleware())

# Инициализация базы данных
conn = sqlite3.connect('training_bot.db')
cursor = conn.cursor()

# Создание таблиц
cursor.execute('''
CREATE TABLE IF NOT EXISTS users (
    id INTEGER PRIMARY KEY,
    telegram_id INTEGER UNIQUE,
    first_name TEXT,
    last_name TEXT
)
''')

cursor.execute('''
CREATE TABLE IF NOT EXISTS workouts (
    id INTEGER PRIMARY KEY,
    user_id INTEGER,
    name TEXT,
    with_weight BOOLEAN,
    FOREIGN KEY (user_id) REFERENCES users (id) ON DELETE CASCADE
)
''')

cursor.execute('''
CREATE TABLE IF NOT EXISTS exercises (
    id INTEGER PRIMARY KEY,
    workout_id INTEGER,
    name TEXT,
    FOREIGN KEY (workout_id) REFERENCES workouts (id) ON DELETE CASCADE
)
''')

# Создание таблицы для хранения веса
cursor.execute('''
CREATE TABLE IF NOT EXISTS weights (
    user_id INTEGER,
    weight REAL,
    data TEXT
)
''')

# Создание таблицы для хранения замеров тела
cursor.execute('''
CREATE TABLE IF NOT EXISTS body_measurements (
    user_id INTEGER,
    data TEXT,
    weight REAL,
    height REAL,
    waist REAL,
    hips REAL,
    chest REAL,
    biceps REAL,
    thigh REAL,
    photo TEXT
)
''')

cursor.execute('''
CREATE TABLE IF NOT EXISTS workout_results (
    id INTEGER PRIMARY KEY,
    user_id INTEGER,
    workout_id INTEGER,
    exercise_id INTEGER,
    sets INTEGER,
    reps INTEGER,
    weight REAL NULL,
    FOREIGN KEY (user_id) REFERENCES users (id),
    FOREIGN KEY (workout_id) REFERENCES workouts (id),
    FOREIGN KEY (exercise_id) REFERENCES exercises (id)
)
''')

# Таблица для хранения расписания тренировок
cursor.execute('''
CREATE TABLE IF NOT EXISTS workout_schedule (
    id INTEGER PRIMARY KEY AUTOINCREMENT,
    user_id INTEGER,
    workout_id INTEGER,
    scheduled_date DATE,
    reminder_sent BOOLEAN DEFAULT 0,
    FOREIGN KEY(workout_id) REFERENCES workouts(id) ON DELETE CASCADE
)''')

# Таблица для хранения выбранных месяцев (опционально)
cursor.execute('''
CREATE TABLE IF NOT EXISTS schedule_months (
    schedule_id INTEGER,
    month INTEGER,
    year INTEGER,
    FOREIGN KEY(schedule_id) REFERENCES workout_schedule(id) ON DELETE CASCADE
)
''')

cursor.execute('''
CREATE TABLE IF NOT EXISTS user_settings (
    user_id INTEGER PRIMARY KEY,
    remind_before_days INTEGER DEFAULT 1,
    remind_hours INTEGER DEFAULT 18,
    remind_minutes INTEGER DEFAULT 0
)''')

cursor.execute('''CREATE TABLE IF NOT EXISTS current_goals
               (user_id INTEGER PRIMARY KEY,
               target_weight REAL,
               start_weight REAL,
               start_date TEXT)''')

cursor.execute('''CREATE TABLE IF NOT EXISTS achievements
               (user_id INTEGER,
               start_weight REAL,
               target_weight REAL,
               start_date TEXT,
               end_date TEXT,
               duration_days INTEGER)''')

# Функция для регистрации пользователя
def register_user(user):
    cursor.execute('INSERT OR IGNORE INTO users (telegram_id, first_name, last_name) VALUES (?, ?, ?)',
                   (user.id, user.first_name, user.last_name))
    conn.commit()

# Состояния для FSM
class WorkoutStates(StatesGroup):
    waiting_for_workout_name = State()  # Начало создания новой тренировки
    waiting_for_weight_choice = State()  # Выбор веса для упражнения
    waiting_for_exercises = State()  # Добавление упражнений в тренировку
    waiting_for_exercise_name = State()  # Ввод названия упражнения
    waiting_for_save_workout = State()  # Сохранение тренировки
    waiting_for_reps = State()  # Ожидание количества повторений
    waiting_for_add_set = State()  # Ожидание добавления подхода
    waiting_for_next_exercise = State()  # Переход к следующему упражнению
    entering_data = State() # Новое состояние для накопления ввода
    waiting_for_workout_selection = State()  # Ожидание выбора тренировки
    waiting_for_date_selection = State()  # Ожидание выбора даты
    waiting_for_edit_action = State()  # Ожидание выбора действия для редактирования
    waiting_for_exercise_selection = State()  # Ожидание выбора упражнения для редактирования
    waiting_for_new_exercise_name = State()  # Ожидание ввода нового названия упражнения
    waiting_for_workout_selection = State()
    waiting_for_month_selection = State()
    waiting_for_day_selection = State()
    waiting_for_schedule_confirmation = State()
    waiting_for_edit_choice = State()
    waiting_for_schedule_workout_choice = State()
    current_month = State()
    current_year = State()
    selected_dates = State()
    workout_id = State()
    choosing_hours = State()
    choosing_minutes = State()
    waiting_for_remind_type = State()
    waiting_for_remind_time = State()
    workout_selected = State()

# Добавляем новые состояния для редактирования
class WorkoutStates2(StatesGroup):
    waiting_for_workout_name = State()
    waiting_for_weight_choice = State()
    waiting_for_exercises = State()
    waiting_for_exercise_name = State()
    workout_selected = State()
    waiting_for_new_exercise_name = State()
    waiting_for_exercise_rename = State()  # Новое состояние

# Группы состояний для инлайн-клавиатур и обычных сообщений
class InlineStates(StatesGroup):
    waiting_for_workout_selection = State()
    waiting_for_exercise_selection = State()
    waiting_for_inline_input = State()

class MessageStates(StatesGroup):
    waiting_for_text_input = State()

# Класс для хранения состояний
class NutritionStates(StatesGroup):
    waiting_for_question = State()

# Состояния для FSM
class WeightStates(StatesGroup):
    waiting_for_weight = State()
    waiting_for_goal = State()
    waiting_for_current_weight = State()

# Уровни активности
activity_levels = {
    'Минимальная активность': 1.2,
    'Низкая активность': 1.375,
    'Средняя активность': 1.55,
    'Высокая активность': 1.725,
    'Очень высокая активность': 1.9
}

# Состояния для FSM
class CalorieStates(StatesGroup):
    waiting_for_height = State()
    waiting_for_weight = State()
    waiting_for_gender = State()
    waiting_for_age = State()
    waiting_for_activity_level = State()

class DeleteStates(StatesGroup):
    confirm_deletion = State()

# Состояния для FSM
class BodyMeasurementStates(StatesGroup):
    waiting_for_weight = State()
    waiting_for_height = State()
    waiting_for_waist = State()
    waiting_for_hips = State()
    waiting_for_chest = State()
    waiting_for_biceps = State()
    waiting_for_thigh = State()
    waiting_for_photo = State()

# Добавим отдельный класс для состояний редактирования
class EditStates(StatesGroup):
    waiting_exercise_rename = State()
    waiting_new_exercise = State()
    
########################### Календарь
# Русские названия
MONTH_NAMES = {
    1: 'Январь', 2: 'Февраль', 3: 'Март', 4: 'Апрель',
    5: 'Май', 6: 'Июнь', 7: 'Июль', 8: 'Август',
    9: 'Сентябрь', 10: 'Октябрь', 11: 'Ноябрь', 12: 'Декабрь'
}

# DAY_NAMES = ["Пн", "Вт", "Ср", "Чт", "Пт", "Сб", "Вс"]

def generate_calendar(year: int, month: int, selected_dates: list):
    markup = types.InlineKeyboardMarkup()
    today = datetime.now().date()
    
    # Заголовок
    markup.row(
        types.InlineKeyboardButton("◀️", callback_data=f"calendar_prev_{year}_{month}"),
        types.InlineKeyboardButton(f"{MONTH_NAMES[month]} {year}", callback_data="ignore"),
        types.InlineKeyboardButton("▶️", callback_data=f"calendar_next_{year}_{month}")
    )
    
    # Собираем все будущие дни месяца
    all_days = []
    for day in range(1, calendar.monthrange(year, month)[1] + 1):
        date_obj = datetime(year, month, day).date()
        if date_obj > today:  # Показываем только будущие даты
            all_days.append(day)
    
    # Разбиваем на ряды по 5 дней
    rows = [all_days[i:i+5] for i in range(0, len(all_days), 5)]
    
    # Добавляем кнопки с днями
    for row_days in rows:
        row = []
        for day in row_days:
            date_str = f"{year}-{month:02d}-{day:02d}"
            emoji = "✅ " if date_str in selected_dates else "⬜️ "
            row.append(types.InlineKeyboardButton(
                f"{emoji}{day}", 
                callback_data=f"calendar_day_{year}_{month}_{day}"
            ))
        markup.row(*row)
    
    # Кнопки управления
    if selected_dates:
        markup.row(
            types.InlineKeyboardButton("❌ Очистить", callback_data="calendar_clear"),
            types.InlineKeyboardButton("✅ Подтвердить", callback_data="calendar_confirm")
        )
    
    return markup

def get_dates_text(selected_dates: list) -> str:
    if not selected_dates:
        return "Выбранные даты: не выбрано"
    
    dates = sorted([datetime.strptime(d, "%Y-%m-%d").day for d in selected_dates])
    return f"Выбранные даты: {', '.join(map(str, dates))}"

# Функция для сброса текущего состояния
async def finish_state_and_reset(state: FSMContext):
    current_state = await state.get_state()
    if current_state is not None:
        await state.finish()

# Обработчик для команды /cancel
@dp.message_handler(commands=['cancel'], state='*')
async def cmd_cancel(message: types.Message, state: FSMContext):
    await state.finish()  # Сбрасываем текущее состояние
    await message.answer("Действие отменено.")

@dp.message_handler(commands=['start'])
async def send_welcome(message: types.Message):
    register_user(message.from_user)
    keyboard = types.ReplyKeyboardMarkup(resize_keyboard=True)
    keyboard.add(types.KeyboardButton("Тренировки"))
    keyboard.row(types.KeyboardButton("Мой вес"), types.KeyboardButton("Питание"))
    keyboard.row(types.KeyboardButton("Профиль"))
    await message.answer("Привет! Я Тренировочный-бот. Я помогу вам создавать и проводить персонализированные тренировки.", reply_markup=keyboard)

# Обработка нажатия на кнопку "Главное меню"
@dp.message_handler(lambda message: message.text == '🏠 Главное меню', state='*')
async def main_menu(message: types.Message, state: FSMContext):
    # Сброс текущего состояния, если оно есть
    current_state = await state.get_state()
    if current_state is not None:
        await state.finish()
    # Создание клавиатуры
    keyboard = types.ReplyKeyboardMarkup(resize_keyboard=True)
    keyboard.add(types.KeyboardButton("Тренировки"))
    keyboard.row(types.KeyboardButton("Мой вес"), types.KeyboardButton("Питание"))
    keyboard.row(types.KeyboardButton("Профиль"))
    await message.answer('Главное меню:', reply_markup=keyboard)

# Обработка нажатия на кнопку "Питание"
@dp.message_handler(lambda message: message.text == 'Питание', state='*')
async def main_menu(message: types.Message, state: FSMContext):
    # Сброс текущего состояния, если оно есть
    current_state = await state.get_state()
    if current_state is not None:
        await state.finish()
    # Создание клавиатуры
    keyboard = types.ReplyKeyboardMarkup(resize_keyboard=True)
    keyboard.row(types.KeyboardButton("AI помощник"), types.KeyboardButton("Калькулятор калорий"))
    keyboard.row(types.KeyboardButton("🏠 Главное меню"))
    await message.answer('Питание:', reply_markup=keyboard)

# Обработка нажатия на кнопку "Тренировки"
@dp.message_handler(lambda message: message.text == 'Тренировки', state='*')
async def main_menu(message: types.Message, state: FSMContext):
    # Сброс текущего состояния, если оно есть
    current_state = await state.get_state()
    if current_state is not None:
        await state.finish()
    # Создание клавиатуры
    keyboard = types.ReplyKeyboardMarkup(resize_keyboard=True)
    keyboard.add(types.KeyboardButton("Начать тренировку"))
    keyboard.row(types.KeyboardButton("Создать тренировку"), types.KeyboardButton("Мои тренировки"))
    keyboard.row(types.KeyboardButton("Расписание тренировок"), types.KeyboardButton("Статистика"))
    keyboard.row(types.KeyboardButton("🏠 Главное меню"))
    await message.answer('Тренировки:', reply_markup=keyboard)

# Обработка нажатия на кнопку "Профиль"
@dp.message_handler(lambda message: message.text == 'Профиль', state='*')
async def main_menu(message: types.Message, state: FSMContext):
    # Сброс текущего состояния, если оно есть
    current_state = await state.get_state()
    if current_state is not None:
        await state.finish()
    # Создание клавиатуры
    keyboard = types.ReplyKeyboardMarkup(resize_keyboard=True)
    keyboard.row(types.KeyboardButton("Замерить тело"), types.KeyboardButton("Просмотр замеров"))
    keyboard.add(types.KeyboardButton("Удалить все данные"))
    keyboard.row(types.KeyboardButton("🏠 Главное меню"))
    await message.answer('Профиль:', reply_markup=keyboard)



#################### Ну пробные напоминания ####################

@dp.message_handler(lambda message: message.text == "Расписание тренировок", state='*')
async def view_raspis(message: types.Message):
    keyboard = ReplyKeyboardMarkup(resize_keyboard=True)
    keyboard.row(types.KeyboardButton("Создать расписание"), types.KeyboardButton("Посмотреть расписание"))
    keyboard.add(types.KeyboardButton("🏠 Главное меню"))
    await message.answer("Расписание тренировок:", reply_markup=keyboard)

@dp.message_handler(lambda message: message.text == "Создать расписание")
async def set_reminder_start(message: types.Message):
    workouts = cursor.execute('SELECT id, name FROM workouts WHERE user_id = ?', 
                            (message.from_user.id,)).fetchall()
    
    if not workouts:
        await message.answer("У вас нет тренировок!")
        return
    
    markup = types.InlineKeyboardMarkup()
    for workout in workouts:
        markup.add(types.InlineKeyboardButton(
            workout[1], callback_data=f"reminder_workout_{workout[0]}"
        ))
    
    await message.answer("Выберите тренировку для расписания:", reply_markup=markup)
    await WorkoutStates.waiting_for_workout_selection.set()

@dp.callback_query_handler(lambda c: c.data.startswith('reminder_workout_'), state=WorkoutStates.waiting_for_workout_selection)
async def process_workout_selection(callback_query: types.CallbackQuery, state: FSMContext):
    workout_id = int(callback_query.data.split('_')[-1])
    user_id = callback_query.from_user.id
    
    existing_dates = cursor.execute('''
        SELECT scheduled_date FROM workout_schedule 
        WHERE user_id = ? AND workout_id = ?''',
        (user_id, workout_id)).fetchall()
    existing_dates = [d[0] for d in existing_dates]
    
    now = datetime.now()
    await state.update_data(
        current_year=now.year,
        current_month=now.month,
        selected_dates=existing_dates,
        workout_id=workout_id
    )
    
    text = [
        "Выберите даты тренировок:",
        get_dates_text(existing_dates),
        "⬜️ - доступные даты",
        "✅ - выбранные даты"
    ]
    
    await callback_query.message.edit_text(
        "\n".join(text),
        reply_markup=generate_calendar(now.year, now.month, existing_dates)
    )
    await WorkoutStates.waiting_for_day_selection.set()

@dp.callback_query_handler(lambda c: c.data.startswith('calendar_'), state=WorkoutStates.waiting_for_day_selection)
async def process_calendar(callback_query: types.CallbackQuery, state: FSMContext):
    data = await state.get_data()
    current_year = data['current_year']
    current_month = data['current_month']
    selected_dates = data['selected_dates']
    workout_id = data['workout_id']
    
    action = callback_query.data.split('_')[1]
    
    if action == 'prev':
        current_month -= 1
        if current_month < 1:
            current_month = 12
            current_year -= 1
            
    elif action == 'next':
        current_month += 1
        if current_month > 12:
            current_month = 1
            current_year += 1
            
    elif action == 'day':
        year = int(callback_query.data.split('_')[2])
        month = int(callback_query.data.split('_')[3])
        day = int(callback_query.data.split('_')[4])
        date_str = f"{year}-{month:02d}-{day:02d}"
        
        if date_str in selected_dates:
            selected_dates.remove(date_str)
        else:
            selected_dates.append(date_str)
            
    elif action == 'clear':
        selected_dates.clear()
        
    elif action == 'confirm':
        user_id = callback_query.from_user.id
        
        # Обновляем базу данных
        cursor.execute('DELETE FROM workout_schedule WHERE user_id = ? AND workout_id = ?', 
                      (user_id, workout_id))
        
        for date_str in selected_dates:
            cursor.execute('''
                INSERT INTO workout_schedule (user_id, workout_id, scheduled_date)
                VALUES (?, ?, ?)''', (user_id, workout_id, date_str))
        
        conn.commit()
        await callback_query.message.edit_text("✅ Расписание успешно сохранено!")
        await state.finish()
        return
    
    # Обновляем состояние
    await state.update_data(
        current_year=current_year,
        current_month=current_month,
        selected_dates=selected_dates
    )
    
    # Формируем текст
    text = [
        "Выберите даты тренировок:",
        get_dates_text(selected_dates),
        "⬜️ - доступные даты",
        "✅ - выбранные даты"
    ]
    
    # Обновляем сообщение
    await callback_query.message.edit_text(
        "\n".join(text),
        reply_markup=generate_calendar(current_year, current_month, selected_dates)
    )

# Просмотр расписания
@dp.message_handler(lambda message: message.text == "Посмотреть расписание")
async def view_schedule(message: types.Message):
    workouts = cursor.execute('SELECT id, name FROM workouts WHERE user_id = ?', 
                            (message.from_user.id,)).fetchall()
    
    if not workouts:
        await message.answer("У вас нет тренировок!")
        return
    
    markup = types.InlineKeyboardMarkup()
    for workout in workouts:
        markup.add(types.InlineKeyboardButton(
            workout[1], callback_data=f"view_schedule_{workout[0]}"
        ))
    
    await message.answer("Выберите тренировку:", reply_markup=markup)
    await WorkoutStates.waiting_for_schedule_workout_choice.set()

# Модифицируем функцию просмотра расписания
@dp.callback_query_handler(lambda c: c.data.startswith('view_schedule_'), 
                          state=WorkoutStates.waiting_for_schedule_workout_choice)
async def show_scheduled_dates(callback_query: types.CallbackQuery, state: FSMContext):
    workout_id = int(callback_query.data.split('_')[-1])
    user_id = callback_query.from_user.id
    
    dates = cursor.execute('''
        SELECT scheduled_date 
        FROM workout_schedule 
        WHERE user_id = ? AND workout_id = ?''',
        (user_id, workout_id)).fetchall()
    
    markup = types.InlineKeyboardMarkup()
    if dates:
        text = "Запланированные даты:\n" + "\n".join(
            [datetime.strptime(d[0], "%Y-%m-%d").strftime("%d.%m.%Y") for d in dates]
        )
        markup.add(types.InlineKeyboardButton("Удалить все", callback_data=f"delete_all_{workout_id}"))
    else:
        text = "Для этой тренировки нет расписания!"
    
    # Добавляем кнопку настройки времени
    markup.row(types.InlineKeyboardButton("⏰ Настроить время напоминания", callback_data="set_reminder_time"))
    
    await callback_query.message.edit_text(text, reply_markup=markup)
    await state.finish()

@dp.callback_query_handler(lambda c: c.data.startswith('delete_all_'))
async def delete_all_schedules(callback_query: types.CallbackQuery):
    workout_id = int(callback_query.data.split('_')[-1])
    user_id = callback_query.from_user.id
    
    cursor.execute('''
        DELETE FROM workout_schedule 
        WHERE user_id = ? AND workout_id = ?''',
        (user_id, workout_id))
    conn.commit()
    
    await callback_query.message.edit_text("Все напоминания удалены!")


################ Настройка напоминаний персональная

# Клавиатура выбора часов
def hours_keyboard(current_hour: int):
    markup = types.InlineKeyboardMarkup()
    markup.row(
        types.InlineKeyboardButton("◀", callback_data="hour_dec"),
        types.InlineKeyboardButton(f"{current_hour:02d}", callback_data="ignore"),
        types.InlineKeyboardButton("▶", callback_data="hour_inc")
    )
    markup.row(types.InlineKeyboardButton("✅ Подтвердить", callback_data="confirm_hours"))
    return markup

# Клавиатура выбора минут
def minutes_keyboard(current_minute: int):
    markup = types.InlineKeyboardMarkup()
    markup.row(
        types.InlineKeyboardButton("◀", callback_data="min_dec"),
        types.InlineKeyboardButton(f"{current_minute:02d}", callback_data="ignore"),
        types.InlineKeyboardButton("▶", callback_data="min_inc")
    )
    markup.row(types.InlineKeyboardButton("✅ Подтвердить", callback_data="confirm_minutes"))
    return markup

# Обработчик выбора типа напоминания
@dp.callback_query_handler(lambda c: c.data in ['remind_type_before', 'remind_type_day'], 
                          state=WorkoutStates.waiting_for_remind_type)
async def process_remind_type(callback_query: types.CallbackQuery, state: FSMContext):
    remind_type = callback_query.data.split('_')[-1]
    await state.update_data(
        remind_before_days=1 if remind_type == 'before' else 0,
        current_hour=18,  # Значение по умолчанию
        current_minute=0
    )
    
    await callback_query.message.answer(
        "Выберите час напоминания:",
        reply_markup=hours_keyboard(18)
    )
    await WorkoutStates.choosing_hours.set()

# Обработчики изменения часов
@dp.callback_query_handler(lambda c: c.data in ['hour_inc', 'hour_dec'], 
                          state=WorkoutStates.choosing_hours)
async def change_hour(callback_query: types.CallbackQuery, state: FSMContext):
    data = await state.get_data()
    current_hour = data['current_hour']
    
    if callback_query.data == 'hour_inc':
        new_hour = (current_hour + 1) % 24
    else:
        new_hour = (current_hour - 1) % 24
    
    await state.update_data(current_hour=new_hour)
    await callback_query.message.edit_reply_markup(hours_keyboard(new_hour))

@dp.callback_query_handler(lambda c: c.data == 'confirm_hours', 
                          state=WorkoutStates.choosing_hours)
async def confirm_hours(callback_query: types.CallbackQuery, state: FSMContext):
    await callback_query.message.answer(
        "Выберите минуты:",
        reply_markup=minutes_keyboard(0)
    )
    await WorkoutStates.choosing_minutes.set()

# Обработчики изменения минут
@dp.callback_query_handler(lambda c: c.data in ['min_inc', 'min_dec'], 
                          state=WorkoutStates.choosing_minutes)
async def change_minute(callback_query: types.CallbackQuery, state: FSMContext):
    data = await state.get_data()
    current_minute = data.get('current_minute', 0)
    steps = [0, 15, 30, 45]
    current_index = steps.index(current_minute)
    
    if callback_query.data == 'min_inc':
        new_index = (current_index + 1) % 4
    else:
        new_index = (current_index - 1) % 4
    
    new_minute = steps[new_index]
    await state.update_data(current_minute=new_minute)
    await callback_query.message.edit_reply_markup(minutes_keyboard(new_minute))

@dp.callback_query_handler(lambda c: c.data == 'confirm_minutes', 
                          state=WorkoutStates.choosing_minutes)
async def confirm_minutes(callback_query: types.CallbackQuery, state: FSMContext):
    data = await state.get_data()
    user_id = callback_query.from_user.id
    
    cursor.execute('''
        INSERT OR REPLACE INTO user_settings 
        (user_id, remind_before_days, remind_hours, remind_minutes) 
        VALUES (?, ?, ?, ?)
    ''', (
        user_id,
        data['remind_before_days'],
        data['current_hour'],
        data['current_minute']
    ))
    conn.commit()
    
    await callback_query.message.answer(
        f"⏰ Напоминания установлены на {data['current_hour']:02d}:{data['current_minute']:02d}"
    )
    await state.finish()

# Обработчик настройки времени
@dp.callback_query_handler(lambda c: c.data == 'set_reminder_time')
async def set_reminder_time(callback_query: types.CallbackQuery):
    markup = types.InlineKeyboardMarkup()
    markup.row(
        types.InlineKeyboardButton("За день", callback_data="remind_type_before"),
        types.InlineKeyboardButton("В день тренировки", callback_data="remind_type_day")
    )
    await callback_query.message.answer("Выберите тип напоминания:", reply_markup=markup)
    await WorkoutStates.waiting_for_remind_type.set()

# Обработчик выбора типа напоминания
@dp.callback_query_handler(state=WorkoutStates.waiting_for_remind_type)
async def process_remind_type(callback_query: types.CallbackQuery, state: FSMContext):
    remind_type = callback_query.data.split('_')[-1]
    await state.update_data(remind_type=remind_type)
    
    await callback_query.message.answer(
        "Введите время в формате ЧЧ:ММ (например, 09:00):"
    )
    await WorkoutStates.waiting_for_remind_time.set()

# Обработчик ввода времени
@dp.message_handler(state=WorkoutStates.waiting_for_remind_time)
async def process_remind_time(message: types.Message, state: FSMContext):
    try:
        # Валидация времени
        datetime.strptime(message.text, "%H:%M")
    except ValueError:
        await message.answer("Неверный формат времени! Попробуйте снова:")
        return
    
    data = await state.get_data()
    remind_type = data['remind_type']
    user_id = message.from_user.id
    
    # Сохраняем настройки
    cursor.execute('''
        INSERT OR REPLACE INTO user_settings 
        (user_id, remind_before_days, remind_time) 
        VALUES (?, ?, ?)
    ''', (
        user_id,
        1 if remind_type == 'before' else 0,
        message.text
    ))
    conn.commit()
    
    await message.answer("Настройки напоминаний сохранены!")
    await state.finish()

# Напоминания
# Обновленная функция проверки напоминаний
async def check_reminders():
    now = datetime.now().replace(second=0, microsecond=0)
    current_time = now.time()
    
    users = cursor.execute('''
        SELECT user_id, remind_before_days, remind_hours, remind_minutes 
        FROM user_settings
    ''').fetchall()
    
    for user in users:
        user_id, before_days, remind_hour, remind_min = user
        
        # Проверяем совпадение времени
        if current_time.hour != remind_hour or current_time.minute != remind_min:
            continue
        
        # Рассчитываем целевую дату
        target_date = now + timedelta(days=before_days)
        target_date_str = target_date.strftime("%Y-%m-%d")
        
        # Получаем тренировки
        schedules = cursor.execute('''
            SELECT w.name 
            FROM workout_schedule ws
            JOIN workouts w ON ws.workout_id = w.id
            WHERE ws.user_id = ? AND ws.scheduled_date = ?''',
            (user_id, target_date_str)).fetchall()
        
        if schedules:
            workouts_list = "\n".join([f"• {s[0]}" for s in schedules])
            await bot.send_message(
                user_id,
                f"🔔 Напоминание {'за день до' if before_days else 'в день'} тренировки!\n"
                f"Запланированные тренировки:\n{workouts_list}"
            )
    
###############################################################





@dp.message_handler(lambda message: message.text == "Создать тренировку", state='*')
async def create_workout(message: types.Message, state: FSMContext):
    await message.answer("Введите название тренировки:")
    await WorkoutStates.waiting_for_workout_name.set()

@dp.message_handler(state=WorkoutStates.waiting_for_workout_name)
async def process_workout_name(message: types.Message, state: FSMContext):
    workout_name = message.text
    user_id = message.from_user.id
    cursor.execute('INSERT INTO workouts (user_id, name) VALUES (?, ?)', (user_id, workout_name))
    conn.commit()
    await state.update_data(workout_name=workout_name, exercises=[])
    await message.answer(f"Тренировка '{workout_name}' создана. Добавьте до 10 упражнений:")
    await WorkoutStates.waiting_for_exercises.set()

@dp.message_handler(state=WorkoutStates.waiting_for_weight_choice)
async def process_weight_choice(message: types.Message, state: FSMContext):
    with_weight = message.text.lower() == "да"
    data = await state.get_data()
    workout_name = data['workout_name']
    cursor.execute('UPDATE workouts SET with_weight = ? WHERE name = ? AND user_id = ?',
                   (with_weight, workout_name, message.from_user.id))
    conn.commit()
    await message.answer(f"Тренировка '{workout_name}' создана {'с весом' if with_weight else 'без веса'}.")
    await message.answer("Добавьте до 10 упражнений (только названия):")
    await WorkoutStates.waiting_for_exercises.set()

@dp.message_handler(state=WorkoutStates.waiting_for_exercises)
async def process_exercises(message: types.Message, state: FSMContext):
    data = await state.get_data()
    exercises = data.get('exercises', [])
    if len(exercises) >= 10:
        await message.reply("Максимум 10 упражнений")
        return
    exercises.append(message.text)
    await state.update_data(exercises=exercises)
    
    # Создаем клавиатуру с вертикальным расположением кнопок
    keyboard = ReplyKeyboardMarkup(
        resize_keyboard=True,
        one_time_keyboard=True  # Опционально - скрыть клавиатуру после выбора
    )
    # Добавляем каждую кнопку в отдельный ряд
    keyboard.row("Добавить упражнение")
    keyboard.row("Сохранить тренировку")
    keyboard.row("🏠 Главное меню")

    await message.answer("Упражнение добавлено.\nВыберите действие:", reply_markup=keyboard)
    await WorkoutStates.waiting_for_exercise_name.set()

@dp.message_handler(lambda message: message.text == "Добавить упражнение", state=WorkoutStates.waiting_for_exercise_name)
async def add_exercise(message: types.Message):
    await message.reply("Введите название упражнения:")
    await WorkoutStates.waiting_for_exercises.set()

@dp.message_handler(lambda message: message.text == "Сохранить тренировку", state=WorkoutStates.waiting_for_exercise_name)
async def save_workout(message: types.Message, state: FSMContext):
    await WorkoutStates.waiting_for_save_workout.set()
    data = await state.get_data()
    workout_name = data['workout_name']
    exercises = data['exercises']
    user_id = message.from_user.id
    workout_id = cursor.execute('SELECT id FROM workouts WHERE name = ? AND user_id = ?',
                                (workout_name, user_id)).fetchone()[0]
    for exercise in exercises:
        cursor.execute('INSERT INTO exercises (workout_id, name) VALUES (?, ?)', (workout_id, exercise))
    conn.commit()
    # Создание клавиатуры
    keyboard = types.ReplyKeyboardMarkup(resize_keyboard=True)
    keyboard.add(types.KeyboardButton("Тренировки"))
    keyboard.add(types.KeyboardButton("🏠 Главное меню"))
    await message.answer("Тренировка сохранена.", reply_markup=keyboard)
    await state.finish()

# Обработчик просмотра тренировок
@dp.message_handler(lambda message: message.text == "Мои тренировки", state='*')
async def view_workouts(message: types.Message, state: FSMContext):
    workouts = cursor.execute('SELECT id, name FROM workouts WHERE user_id = ?', (message.from_user.id,)).fetchall()
    if workouts:
        keyboard = ReplyKeyboardMarkup(resize_keyboard=True)
        for workout in workouts:
            keyboard.add(KeyboardButton(workout[1]))
        await message.answer("Выберите тренировку:", reply_markup=keyboard)
        await WorkoutStates2.workout_selected.set()
    else:
        await message.reply("У вас пока нет тренировок.")
        await state.finish()

# Обработчик выбранной тренировки
@dp.message_handler(state=WorkoutStates2.workout_selected)
async def show_workout_exercises(message: types.Message, state: FSMContext):
    user_id = message.from_user.id
    workout_name = message.text
    
    workout = cursor.execute('''SELECT id FROM workouts 
                             WHERE name = ? AND user_id = ?''', (workout_name, user_id)).fetchone()
    
    if not workout:
        await message.answer("Тренировка не найдена")
        await state.finish()
        return
    
    workout_id = workout[0]
    exercises = cursor.execute('''SELECT name FROM exercises 
                               WHERE workout_id = ?''', (workout_id,)).fetchall()
    
    exercise_text = "\n".join([f"▫️ {ex[0]}" for ex in exercises]) if exercises else "▫️ Нет упражнений"
    response = f"🏋️ Тренировка: {workout_name}\n\nУпражнения:\n{exercise_text}"
    
    # Inline-клавиатура для действий с тренировкой
    inline_kb = InlineKeyboardMarkup(row_width=2)
    inline_kb.add(
        InlineKeyboardButton("✏️ Редактировать", callback_data=f"edit_{workout_id}"),
        InlineKeyboardButton("🗑 Удалить", callback_data=f"delete_workout_{workout_id}")
    )
    
    # Reply-клавиатура для навигации
    reply_kb = ReplyKeyboardMarkup(
        resize_keyboard=True,
        keyboard=[
            [KeyboardButton("Тренировки")],
            [KeyboardButton("🏠 Главное меню")]
        ]
    )
    
    await message.answer(response, reply_markup=inline_kb)
    await message.answer("Выберите раздел:", reply_markup=reply_kb)
    await state.finish()

# Обработчик редактирования тренировки
@dp.callback_query_handler(lambda c: c.data.startswith('edit_'))
async def edit_workout(callback: types.CallbackQuery):
    workout_id = int(callback.data.split('_')[1])
    exercises = cursor.execute('SELECT id, name FROM exercises WHERE workout_id = ?', (workout_id,)).fetchall()
    
    keyboard = InlineKeyboardMarkup(row_width=1)
    for exercise in exercises:
        keyboard.add(InlineKeyboardButton(
            f"✏️ {exercise[1]}", 
            callback_data=f"ex_{exercise[0]}"  # Упрощенный префикс
        ))
    
    keyboard.row(
        InlineKeyboardButton("➕ Добавить упражнение", callback_data=f"add_ex_{workout_id}")
    )
    
    await callback.message.edit_text(
        "🗂 Список упражнений для редактирования:",
        reply_markup=keyboard
    )

# Обработчик выбора упражнения
@dp.callback_query_handler(lambda c: c.data.startswith('ex_'))
async def edit_exercise(callback: types.CallbackQuery):
    exercise_id = int(callback.data.split('_')[1])
    exercise = cursor.execute('''SELECT name, workout_id 
                              FROM exercises WHERE id = ?''', (exercise_id,)).fetchone()
    
    # Получаем workout_id из упражнения
    workout_id = exercise[1]
    
    keyboard = InlineKeyboardMarkup(row_width=2)
    keyboard.add(
        InlineKeyboardButton("✏️ Переименовать", callback_data=f"rename_{exercise_id}"),
        InlineKeyboardButton("🗑 Удалить", callback_data=f"del_ex_{exercise_id}")
    )
    # Передаем workout_id в кнопку Назад
    keyboard.add(InlineKeyboardButton("🔙 Назад", callback_data=f"edit_{workout_id}"))
    
    await callback.message.edit_text(
        f"⚙️ Настройки упражнения: {exercise[0]}",
        reply_markup=keyboard
    )

# Обработчик переименования упражнения
@dp.callback_query_handler(lambda c: c.data.startswith('rename_'))
async def rename_exercise_start(callback: types.CallbackQuery, state: FSMContext):
    exercise_id = int(callback.data.split('_')[1])
    await state.update_data(exercise_id=exercise_id)
    await WorkoutStates2.waiting_for_exercise_rename.set()
    await callback.message.answer("Введите новое название упражнения:")

@dp.message_handler(state=WorkoutStates2.waiting_for_exercise_rename)
async def rename_exercise_finish(message: types.Message, state: FSMContext):
    data = await state.get_data()
    exercise_id = data.get('exercise_id')
    
    if not exercise_id:
        await message.answer("❌ Ошибка: упражнение не найдено")
        await state.finish()
        return
    
    new_name = message.text
    cursor.execute('UPDATE exercises SET name = ? WHERE id = ?', (new_name, exercise_id))
    conn.commit()
    
    await message.answer(
        f"✅ Успешно обновлено: {new_name}",
        reply_markup=ReplyKeyboardMarkup(
        resize_keyboard=True,  # Делаем клавиатуру компактной
        keyboard=[
            [KeyboardButton("Тренировки")],
            [KeyboardButton("🏠 Главное меню")]
        ],
        )
    )

# Обработчик удаления упражнения
@dp.callback_query_handler(lambda c: c.data.startswith('del_ex_'))
async def delete_exercise(callback: types.CallbackQuery):
    exercise_id = int(callback.data.split('_')[2])
    exercise = cursor.execute('SELECT name FROM exercises WHERE id = ?', (exercise_id,)).fetchone()
    
    if not exercise:
        await callback.answer("Упражнение не найдено!")
        return
    
    cursor.execute('DELETE FROM exercises WHERE id = ?', (exercise_id,))
    conn.commit()
    
    await callback.message.answer(
        f"🗑 Удалено: {exercise[0]}", 
        reply_markup=ReplyKeyboardMarkup(
            resize_keyboard=True,  # Делаем клавиатуру компактной
            keyboard=[
            [KeyboardButton("Тренировки")],
            [KeyboardButton("🏠 Главное меню")]
        ],
        )
    )

@dp.callback_query_handler(lambda c: c.data == 'workouts_list')
async def back_to_workouts_list(callback: types.CallbackQuery):
    user_id = callback.from_user.id
    workouts = cursor.execute('SELECT id, name FROM workouts WHERE user_id = ?', (user_id,)).fetchall()
    
    keyboard = InlineKeyboardMarkup(row_width=1)
    for workout in workouts:
        keyboard.add(InlineKeyboardButton(
            workout[1], 
            callback_data=f"view_{workout[0]}"
        ))
    
    await callback.message.edit_text(
        "🏋️ Ваши тренировки:",
        reply_markup=keyboard
    )
    
# Обработчик добавления упражнения
@dp.callback_query_handler(lambda c: c.data.startswith('add_ex_'))
async def add_exercise_start(callback: types.CallbackQuery, state: FSMContext):
    workout_id = int(callback.data.split('_')[2])
    await state.update_data(workout_id=workout_id)
    await WorkoutStates2.waiting_for_new_exercise_name.set()
    await callback.message.answer("Введите название нового упражнения:")

@dp.message_handler(state=WorkoutStates2.waiting_for_new_exercise_name)
async def add_exercise_finish(message: types.Message, state: FSMContext):
    data = await state.get_data()
    workout_id = data.get('workout_id')
    
    if not workout_id:
        await message.answer("❌ Ошибка: тренировка не найдена")
        await state.finish()
        return
    
    name = message.text.strip()
    if len(name) < 2:
        await message.answer("❗ Название должно быть не короче 2 символов")
        return
    
    cursor.execute('INSERT INTO exercises (workout_id, name) VALUES (?, ?)', (workout_id, name))
    conn.commit()
    
    await message.answer(
        f"✅ Добавлено: {name}", 
        reply_markup=ReplyKeyboardMarkup(
            resize_keyboard=True,  # Делаем клавиатуру компактной
            keyboard=[
            [KeyboardButton("Тренировки")],
            [KeyboardButton("🏠 Главное меню")]
        ],
        )
    )

# Обработчик удаления тренировки
@dp.callback_query_handler(lambda c: c.data.startswith('delete_workout_'))
async def confirm_delete_workout(callback: types.CallbackQuery):
    workout_id = int(callback.data.split('_')[2])
    workout = cursor.execute('SELECT name FROM workouts WHERE id = ?', (workout_id,)).fetchone()
    
    if not workout:
        await callback.answer("Тренировка не найдена!")
        return
    
    keyboard = InlineKeyboardMarkup(row_width=2)
    keyboard.add(
        InlineKeyboardButton("✅ Да", callback_data=f"confirm_del_{workout_id}"),
        InlineKeyboardButton("❌ Нет", callback_data="cancel_del")
    )
    
    await callback.message.edit_text(
        f"⚠️ Удалить тренировку «{workout[0]}»? Все упражнения будут удалены!",
        reply_markup=keyboard
    )

@dp.callback_query_handler(lambda c: c.data.startswith('confirm_del_'))
async def delete_workout(callback: types.CallbackQuery):
    workout_id = int(callback.data.split('_')[2])
    
    cursor.execute('DELETE FROM workouts WHERE id = ?', (workout_id,))
    cursor.execute('DELETE FROM exercises WHERE workout_id = ?', (workout_id,))
    conn.commit()
    
    await callback.message.edit_text("✅ Тренировка удалена")
    await callback.answer()

@dp.callback_query_handler(lambda c: c.data == 'cancel_del')
async def cancel_delete(callback: types.CallbackQuery):
    await callback.message.edit_text("❌ Удаление отменено")
    await callback.answer()

############# Запись и просмотр веса

def create_weight_submenu():
    keyboard = types.ReplyKeyboardMarkup(resize_keyboard=True)
    keyboard.row(types.KeyboardButton("Записать вес"), types.KeyboardButton("История веса"))
    keyboard.row(types.KeyboardButton("Поставить цель"), types.KeyboardButton("График веса"))
    keyboard.add(types.KeyboardButton("🏠 Главное меню"))
    return keyboard

def create_progress_bar(percentage):
    progress = min(max(percentage, 0), 100)
    filled = '🟦' * int(progress // 10)
    empty = '⬜️' * (10 - int(progress // 10))
    return f"{filled}{empty} {progress:.1f}%"

def calculate_progress(current, start, target):
    if target < start:  # Похудение
        if current <= target: return 100.0
        return ((start - current) / (start - target)) * 100
    else:  # Набор веса
        if current >= target: return 100.0
        return ((current - start) / (target - start)) * 100

async def check_and_congratulate(user_id, current_weight):
    cursor.execute("SELECT target_weight, start_weight, start_date FROM current_goals WHERE user_id = ?", (user_id,))
    goal = cursor.fetchone()
    
    if goal:
        target, start, start_date = goal
        progress = calculate_progress(current_weight, start, target)
        
        if progress >= 100:
            end_date = datetime.now().strftime('%d.%m.%Y')
            start_date_obj = datetime.strptime(start_date, '%d.%m.%Y')
            end_date_obj = datetime.strptime(end_date, '%d.%m.%Y')
            duration = (end_date_obj - start_date_obj).days

            cursor.execute('''INSERT INTO achievements VALUES (?,?,?,?,?,?)''',
                          (user_id, start, target, start_date, end_date, duration))
            cursor.execute("DELETE FROM current_goals WHERE user_id = ?", (user_id,))
            conn.commit()

            await bot.send_message(
                user_id,
                f"🎉 Цель достигнута!\n"
                f"▫️ Начальный вес: {start} кг\n"
                f"▫️ Текущий вес: {current_weight} кг\n"
                f"▫️ Цель: {target} кг\n"
                f"▫️ Достигнуто за: {duration} дней\n\n"
                "Хотите поставить новую цель?",
                reply_markup=types.InlineKeyboardMarkup().row(
                    types.InlineKeyboardButton("Да", callback_data="set_new_goal"),
                    types.InlineKeyboardButton("Нет", callback_data="cancel_goal")
                ))

# Обработчик кнопки "Мой вес"
@dp.message_handler(lambda message: message.text == "Мой вес")
async def weight_menu(message: types.Message):
    await message.answer("Меню веса:", reply_markup=create_weight_submenu())

@dp.message_handler(lambda message: message.text == "История веса")
async def show_weight_history(message: types.Message):
    user_id = message.from_user.id
    weights = cursor.execute('SELECT weight, data FROM weights WHERE user_id = ? ORDER BY data DESC LIMIT 10', (user_id,)).fetchall()

    if not weights:
        await message.answer("История веса пуста")
        return

    response = "📊 Последние 10 записей:\n\n"
    for weight, date in weights:
        response += f"▫️ {date}: {weight} кг\n"

    cursor.execute("SELECT target_weight, start_weight FROM current_goals WHERE user_id = ?", (user_id,))
    goal = cursor.fetchone()
    
    if goal:
        target, start = goal
        current = weights[0][0]
        progress = calculate_progress(current, start, target)
        response += f"\n{create_progress_bar(progress)}\nЦель: {target} кг"
    
    await message.answer(response)

@dp.message_handler(lambda message: message.text == "Записать вес")
async def start_weight_input(message: types.Message):
    await message.answer("Введите ваш текущий вес (кг):")
    await WeightStates.waiting_for_weight.set()

@dp.message_handler(state=WeightStates.waiting_for_weight)
async def process_weight(message: types.Message, state: FSMContext):
    try:
        weight = float(message.text.replace(',', '.'))
        if weight <= 0:
            raise ValueError
    except ValueError:
        await message.answer("❌ Некорректный формат. Введите вес в формате 70.5 или 70,5")
        return

    user_id = message.from_user.id
    date = datetime.now().strftime('%d.%m.%Y')
    
    cursor.execute('''INSERT INTO weights (user_id, weight, data)
                  VALUES (?, ?, ?)''',
              (user_id, weight, date))

    # Проверка и отображение прогресса
    cursor.execute("SELECT target_weight, start_weight FROM current_goals WHERE user_id = ?", (user_id,))
    goal = cursor.fetchone()
    
    if goal:
        target, start = goal
        progress = calculate_progress(weight, start, target)
        await message.answer(f"📈 Прогресс:\n{create_progress_bar(progress)}")
    
    await check_and_congratulate(user_id, weight)
    await message.answer("✅ Вес успешно сохранен!", reply_markup=create_weight_submenu())
    await state.finish()

@dp.message_handler(lambda message: message.text == "Поставить цель")
async def start_goal_setup(message: types.Message):
    user_id = message.from_user.id

    # Получаем последний вес для всех сценариев
    cursor.execute("SELECT weight FROM weights WHERE user_id = ? ORDER BY data DESC LIMIT 1", (user_id,))
    last_weight = cursor.fetchone()
    
    # Проверяем существующую цель
    cursor.execute("SELECT target_weight, start_weight, start_date FROM current_goals WHERE user_id = ?", (user_id,))
    goal = cursor.fetchone()

    if goal:
        target, start, start_date = goal
        progress_msg = (
            f"📌 Текущая цель:\n"
            f"▫️ Начальный вес: {start} кг\n"
            f"▫️ Целевой вес: {target} кг\n"
            f"▫️ Дата начала: {start_date}\n\n"
            f"💡 Ваш последний зафиксированный вес: {last_weight[0]} кг"
        )
        
        # Создаем inline-клавиатуру
        keyboard = types.InlineKeyboardMarkup()
        keyboard.add(types.InlineKeyboardButton("Создать новую цель", callback_data="create_new_goal"))
        keyboard.add(types.InlineKeyboardButton("🗑️ Удалить цель", callback_data="delete_goal"))
        
        await message.answer(progress_msg, reply_markup=keyboard)
        return

    # Если цели нет, показываем последний вес и запрашиваем цель
    if not last_weight:
        await message.answer("❌ Сначала запишите ваш текущий вес!")
        return
    
    await message.answer(
        f"💡 Ваш последний зафиксированный вес: {last_weight[0]} кг\n"
        "Введите целевую массу тела (кг):"
    )
    await WeightStates.waiting_for_goal.set()

@dp.callback_query_handler(lambda c: c.data == "create_new_goal")
async def create_new_goal(callback: types.CallbackQuery):
    user_id = callback.from_user.id
    
    # Удаляем текущую цель
    cursor.execute("DELETE FROM current_goals WHERE user_id = ?", (user_id,))
    conn.commit()
    
    # Получаем последний вес
    cursor.execute("SELECT weight FROM weights WHERE user_id = ? ORDER BY data DESC LIMIT 1", (user_id,))
    last_weight = cursor.fetchone()
    
    if not last_weight:
        await callback.message.answer("❌ Сначала запишите ваш текущий вес!")
        return
    
    # Формируем сообщение с последним весом
    await callback.message.answer(
        f"Ваш последний зафиксированный вес: {last_weight[0]} кг\n"
        "Введите целевую массу тела (кг):"
    )
    await WeightStates.waiting_for_goal.set()
    await callback.answer()

@dp.callback_query_handler(lambda c: c.data == "delete_goal")
async def delete_goal(callback: types.CallbackQuery):
    user_id = callback.from_user.id
    cursor.execute("DELETE FROM current_goals WHERE user_id = ?", (user_id,))
    conn.commit()
    
    # Редактируем исходное сообщение и отправляем уведомление
    msg = await callback.message.edit_text("✅ Цель успешно удалена!", reply_markup=None)
    
    # Удаляем сообщение через 3 секунды
    await asyncio.sleep(3)
    await bot.delete_message(chat_id=callback.message.chat.id, message_id=msg.message_id)
    await callback.answer()

@dp.message_handler(state=WeightStates.waiting_for_goal)
async def process_goal(message: types.Message, state: FSMContext):
    try:
        target = float(message.text.replace(',', '.'))
        if target <= 0:
            raise ValueError
    except ValueError:
        await message.answer("❌ Некорректный формат. Введите число в формате 65.0 или 65")
        return

    user_id = message.from_user.id
    date = datetime.now().strftime('%d.%m.%Y')
    
    # Получаем текущий вес
    cursor.execute("SELECT weight FROM weights WHERE user_id = ? ORDER BY data DESC LIMIT 1", (user_id,))
    result = cursor.fetchone()
    
    if not result:
        await message.answer("❌ Сначала запишите ваш текущий вес!")
        await state.finish()
        return
    
    current = result[0]
    
    # Обновляем запись цели
    cursor.execute('''INSERT OR REPLACE INTO current_goals 
                    (user_id, target_weight, start_weight, start_date)
                    VALUES (?, ?, ?, ?)''', 
                  (user_id, target, current, date))
    conn.commit()
    
    await message.answer(
        f"🎯 Новая цель установлена!\n"
        f"▫️ Текущий вес: {current} кг\n"
        f"▫️ Целевой вес: {target} кг\n"
        f"▫️ Дата начала: {date}")
    await state.finish()

@dp.callback_query_handler(lambda c: c.data == "set_new_goal")
async def set_new_goal(callback: types.CallbackQuery):
    await callback.message.edit_reply_markup()
    await start_goal_setup(callback.message)

@dp.callback_query_handler(lambda c: c.data == "cancel_goal")
async def cancel_goal(callback: types.CallbackQuery):
    await callback.message.edit_reply_markup()
    await callback.message.answer("Статистика сохранена в достижениях!")

########################################## Конец #############################################################




@dp.message_handler(lambda message: message.text == "Начать тренировку", state='*')
async def start_workout(message: types.Message):
    workouts = cursor.execute('SELECT id, name FROM workouts WHERE user_id = ?', (message.from_user.id,)).fetchall()
    if workouts:
        keyboard = types.InlineKeyboardMarkup(row_width=1)
        for workout in workouts:
            keyboard.add(types.InlineKeyboardButton(workout[1], callback_data=f"start_workout_{workout[0]}"))
        await message.answer("Выберите тренировку:", reply_markup=keyboard)
    else:
        await message.reply("У вас пока нет тренировок.")

@dp.callback_query_handler(lambda c: c.data.startswith('start_workout_'), state='*')
async def process_start_workout(callback_query: types.CallbackQuery, state: FSMContext):
    workout_id = int(callback_query.data.split('_')[2])
    exercises = cursor.execute('SELECT id, name FROM exercises WHERE workout_id = ?', (workout_id,)).fetchall()
    if exercises:
        session_id = str(uuid.uuid4())  # Генерация уникального ID сессии
        # Записываем время начала в новую таблицу
        cursor.execute('''
            INSERT INTO workout_sessions 
            (session_id, user_id, start_date)
            VALUES (?, ?, ?)
        ''', (session_id, callback_query.from_user.id, datetime.now()))
        conn.commit()
        await state.update_data(session_id=session_id)
        keyboard = types.InlineKeyboardMarkup(row_width=1)
        for exercise in exercises:
            keyboard.add(types.InlineKeyboardButton(exercise[1], callback_data=f"exercise_{exercise[0]}"))
        await bot.send_message(callback_query.from_user.id, "Выберите упражнение:", reply_markup=keyboard)
    else:
        await bot.send_message(callback_query.from_user.id, "В этой тренировке нет упражнений.")

# Функция для создания клавиатуры с учетом текущего этапа ввода
def create_input_keyboard():
    keyboard = InlineKeyboardMarkup(row_width=3)
    buttons = [InlineKeyboardButton(str(i), callback_data=f"number_{i}") for i in range(1,10)]
    keyboard.add(*buttons)
    keyboard.row(
        InlineKeyboardButton("0", callback_data="number_0"),
        InlineKeyboardButton(".", callback_data="dot"),
        InlineKeyboardButton("Ввести вес ➡️", callback_data="start_weight")
    )
    keyboard.row(
        InlineKeyboardButton("Очистить ❌", callback_data="input_clear"),
        InlineKeyboardButton("Готово ✅", callback_data="done")
    )
    return keyboard

# Функция для обновления сообщения с текущими данными
async def update_input_message(bot: Bot, chat_id: int, message_id: int, reps: str, weight: str):
    try:
        text = (
            f"🏋️ Введите данные подхода:\n\n"
            f"Повторения: {reps or '0'}\n"
            f"Вес: {weight or '0'} кг\n\n"
            "Используйте кнопки ниже:"
        )
        
        await bot.edit_message_text(
            chat_id=chat_id,
            message_id=message_id,
            text=text,
            reply_markup=create_input_keyboard()
        )
    except MessageNotModified:
        # Игнорируем ошибку, если сообщение не изменилось
        pass
    except Exception as e:
        logging.error(f"Error updating message: {e}")
        await bot.send_message(chat_id, "⚠️ Произошла ошибка обновления")

# Обработчик выбора упражнения
@dp.callback_query_handler(lambda c: c.data.startswith('exercise_'), state='*')
async def process_exercise(callback_query: types.CallbackQuery, state: FSMContext):
    exercise_id = int(callback_query.data.split('_')[1])
    exercise_name = cursor.execute('SELECT name FROM exercises WHERE id = ?', (exercise_id,)).fetchone()[0]
    with_weight = cursor.execute('SELECT with_weight FROM workouts WHERE id = (SELECT workout_id FROM exercises WHERE id = ?)', (exercise_id,)).fetchone()[0]
    
    # Инициализируем данные
    await state.update_data(
        reps_input="",
        weight_input="",
        is_weight_input=False,
        with_weight=with_weight
    )
    
    # Отправляем начальное сообщение
    msg = await bot.send_message(
        callback_query.from_user.id,
        "🏋️ Введите данные:\n\nКол-во повторений: 0\nВес: 0 кг\n\nИспользуйте кнопки ниже:",
        reply_markup=create_input_keyboard()
    )
    
    await state.update_data(
        exercise_id=exercise_id,
        keyboard_message_id=msg.message_id,
        set_number=1  # Начинаем с первого подхода
    )
    await WorkoutStates.entering_data.set()

# Обработчики кнопок ввода
@dp.callback_query_handler(lambda c: c.data.startswith('number_'), state=WorkoutStates.entering_data)
async def process_number(callback: types.CallbackQuery, state: FSMContext):
    try:
        number = callback.data.split('_')[1]
        data = await state.get_data()
        
        # Определяем тип ввода
        field = 'weight_input' if data.get('is_weight_input') else 'reps_input'
        current = data.get(field, '')
        
        # Проверка максимальной длины
        if len(current) >= 5:
            await callback.answer("Максимум 5 цифр")
            return
            
        await state.update_data({field: current + number})
        await update_current_state(callback, state)
        
    except Exception as e:
        logging.error(f"Number input error: {e}")
        await callback.answer("Ошибка ввода")

@dp.callback_query_handler(lambda c: c.data == 'dot', state=WorkoutStates.entering_data)
async def process_dot(callback_query: types.CallbackQuery, state: FSMContext):
    data = await state.get_data()
    if data['is_weight_input'] and '.' not in data['weight_input']:
        await state.update_data(weight_input=data['weight_input'] + '.')
        await update_current_state(callback_query, state)

@dp.callback_query_handler(lambda c: c.data == 'start_weight', state=WorkoutStates.entering_data)
async def start_weight_input(callback: types.CallbackQuery, state: FSMContext):
    try:
        # Обновляем состояние перед изменением сообщения
        await state.update_data(is_weight_input=True)
        
        # Получаем текущие данные
        data = await state.get_data()
        reps = data.get('reps_input', '0')
        weight = data.get('weight_input', '0')
        
        # Обновляем сообщение только если данные изменились
        if reps == '0' and weight == '0':
            return
        
        await update_input_message(
            callback.bot,
            callback.from_user.id,
            data['keyboard_message_id'],
            reps,
            weight
        )
        await callback.answer("Введите вес")
    except Exception as e:
        logging.error(f"Error in start_weight: {e}")
        await callback.answer("Ошибка, попробуйте снова")

@dp.callback_query_handler(lambda c: c.data == 'input_clear', state=WorkoutStates.entering_data)
async def process_clear(callback_query: types.CallbackQuery, state: FSMContext):
    data = await state.get_data()
    if data['is_weight_input']:
        await state.update_data(weight_input="")
    else:
        await state.update_data(reps_input="")
    await update_current_state(callback_query, state)

# Обновление состояния и сообщения
async def update_current_state(callback: types.CallbackQuery, state: FSMContext):
    try:
        data = await state.get_data()
        await update_input_message(
            bot=callback.bot,
            chat_id=callback.from_user.id,
            message_id=data['keyboard_message_id'],
            reps=data.get('reps_input', '0'),
            weight=data.get('weight_input', '0')
        )
    except KeyError as e:
        logging.error(f"Missing key in state: {e}")
        await callback.answer("Ошибка состояния, начните заново")
        await state.finish()

# Обработчик завершения ввода
@dp.callback_query_handler(lambda c: c.data == 'done', state=WorkoutStates.entering_data)
async def process_done(callback: types.CallbackQuery, state: FSMContext):
    data = await state.get_data()
    
    try:
        # Проверяем наличие session_id
        if 'session_id' not in data:
            await callback.message.answer("Ошибка сессии. Начните заново.")
            await state.finish()
            return
        # Получаем workout_id из базы данных
        exercise_id = data['exercise_id']
        workout_id = cursor.execute(
            'SELECT workout_id FROM exercises WHERE id = ?', 
            (exercise_id,)
        ).fetchone()[0]

        # Валидация ввода
        reps = int(data['reps_input']) if data['reps_input'] else 0
        weight = float(data['weight_input']) if data['weight_input'] else None
        
        if reps <= 0:
            raise ValueError("Количество повторений должно быть больше 0")

        # Сохранение с учетом session_id
        cursor.execute('''
            INSERT INTO workout_results 
            (user_id, workout_id, exercise_id, sets, reps, weight, workout_session_id) 
            VALUES (?, ?, ?, ?, ?, ?, ?)
        ''', (
            callback.from_user.id,
            workout_id,
            exercise_id,
            data['set_number'],
            reps,
            weight,
            data['session_id']  # Добавляем session_id
        ))
        conn.commit()

        # Удаление клавиатуры ввода
        await bot.delete_message(
            chat_id=callback.from_user.id,
            message_id=data['keyboard_message_id']
        )

        # Формирование ответа
        response = f"✅ Подход {data['set_number']} сохранен!\nПовторения: {reps}"
        if weight:
            response += f"\nВес: {weight} кг"
        
        await callback.message.answer(response)

        # Обновление состояния для следующего подхода
        await state.update_data(
            set_number=data['set_number'] + 1,
            reps_input="",
            weight_input=""
        )

        # Показ меню действий
        keyboard = ReplyKeyboardMarkup(resize_keyboard=True)
        keyboard.row("Добавить подход ➕", "Следующее упражнение ➡️")
        keyboard.add("Закончить тренировку 🏁")
        
        await callback.message.answer(
            "Выберите действие:", 
            reply_markup=keyboard
        )
        await WorkoutStates.waiting_for_next_exercise.set()

    except ValueError as e:
        # Обработка ошибок ввода
        error_msg = f"❌ Ошибка: {str(e)}"
        await callback.message.answer(error_msg)
        await WorkoutStates.entering_data.set()  # Возврат в состояние ввода

    except Exception as e:
        # Логирование критических ошибок
        logging.error(f"Critical error: {str(e)}")
        await callback.message.answer("⚠️ Произошла системная ошибка")
        await state.finish()

@dp.message_handler(lambda message: message.text == "Добавить подход ➕", state=WorkoutStates.waiting_for_next_exercise)
async def add_set(message: types.Message, state: FSMContext):
    data = await state.get_data()
    
    # Проверяем наличие session_id
    if 'session_id' not in data:
        await message.answer("Ошибка сессии. Начните заново.")
        await state.finish()
        return

    exercise_id = data['exercise_id']
    session_id = data['session_id']

    # Новый запрос с учетом session_id
    set_number = cursor.execute(
        '''SELECT COALESCE(MAX(sets), 0) 
        FROM workout_results 
        WHERE exercise_id = ? AND workout_session_id = ?''',
        (exercise_id, session_id)
    ).fetchone()[0] + 1


    # Получаем название упражнения
    exercise_name = cursor.execute(
        'SELECT name FROM exercises WHERE id = ?',
        (exercise_id,)
    ).fetchone()[0]

    # Создаем новое сообщение с клавиатурой
    msg = await message.answer(
        f"🏋️ {exercise_name} - подход {set_number}\n\n"
        "Введите данные:",
        reply_markup=create_input_keyboard()
    )

    # Обновляем состояние
    await state.update_data(
        set_number=set_number,
        keyboard_message_id=msg.message_id,
        reps_input="",
        weight_input="",
        is_weight_input=False
    )
    await WorkoutStates.entering_data.set()

@dp.message_handler(lambda message: message.text == "Следующее упражнение ➡️", state=WorkoutStates.waiting_for_next_exercise)
async def next_exercise(message: types.Message, state: FSMContext):
    state_data = await state.get_data()
    exercise_id = state_data['exercise_id']
    session_id = state_data['session_id']
    workout_id = cursor.execute('SELECT workout_id FROM exercises WHERE id = ?', (exercise_id,)).fetchone()[0]
    completed_exercise_ids = cursor.execute('SELECT DISTINCT exercise_id FROM workout_results WHERE user_id = ? AND workout_id = ? AND workout_session_id = ?', (message.from_user.id, workout_id, session_id)).fetchall()
    remaining_exercises = cursor.execute('SELECT id, name FROM exercises WHERE workout_id = ? AND id NOT IN ({0})'.format(','.join(['?'] * len(completed_exercise_ids))), (workout_id,) + tuple([x[0] for x in completed_exercise_ids])).fetchall()

    if remaining_exercises:
        keyboard = types.InlineKeyboardMarkup(row_width=1)
        for exercise in remaining_exercises:
            keyboard.add(types.InlineKeyboardButton(exercise[1], callback_data=f"exercise_{exercise[0]}"))
        await message.answer("Выберите следующее упражнение:", reply_markup=keyboard)
    else:
        await message.answer("Вы выполнили все упражнения, нажмите 'Закончить тренировку'")
        #await state.finish()

@dp.message_handler(lambda message: message.text == "Закончить тренировку 🏁", state=WorkoutStates.waiting_for_next_exercise)
async def finish_training(message: types.Message, state: FSMContext):
    data = await state.get_data()
    # Проверяем наличие session_id
    if 'session_id' not in data:
        await message.answer("Ошибка сессии. Начните заново.")
        await state.finish()
        return
    session_id = data['session_id']
    # Обновляем время окончания тренировки
    cursor.execute('''
        UPDATE workout_sessions
        SET end_date = ?
        WHERE session_id = ?
    ''', (datetime.now(), session_id))
    conn.commit()

    try:
        # Получаем все записи для текущей сессии
        results = cursor.execute(
        '''SELECT exercise_id, sets, reps, weight 
        FROM workout_results 
        WHERE workout_session_id = ? 
        ORDER BY exercise_id, sets''',
        (session_id,)
        ).fetchall()

        if not results:
            await message.answer("Нет данных для отображения")
            return

        # Группируем по упражнениям
        report = []
        current_exercise = None
        for exercise_id, set_num, reps, weight in results:
            # Получаем название упражнения только при изменении
            if exercise_id != current_exercise:
                exercise_name = cursor.execute(
                    'SELECT name FROM exercises WHERE id = ?',
                    (exercise_id,)
                ).fetchone()[0]
                report.append(f"➤ *{exercise_name}*")
                current_exercise = exercise_id
            
            # Форматируем подход
            line = f"   Подход {set_num}: {reps} повторений"
            if weight:
                line += f" ({weight} кг)"
            report.append(line)

        # Отправляем результат
        await message.answer(
            "🏁 *Результаты тренировки:*\n\n" + "\n".join(report),
            parse_mode=ParseMode.MARKDOWN
        )

        # Возврат в главное меню
        keyboard = ReplyKeyboardMarkup(resize_keyboard=True)
        keyboard.add("🏠 Главное меню")
        await message.answer("Тренировка завершена!", reply_markup=keyboard)

    except Exception as e:
        logging.error(f"Ошибка: {str(e)}")
        await message.answer("⚠️ Ошибка при формировании отчета")
    
    await state.finish()

@dp.message_handler(lambda message: message.text == "Статистика", state='*')
async def view_stats(message: types.Message):
    keyboard = ReplyKeyboardMarkup(resize_keyboard=True)
    keyboard.row("📅 По датам", "📊 Прогресс")
    keyboard.add("🏠 Главное меню")
    await message.answer("Выберите тип статистики:", reply_markup=keyboard)

@dp.message_handler(lambda message: message.text == "📅 По датам", state='*')
async def show_date_stats(message: types.Message):
    try:
        # Получаем даты из workout_sessions
        dates = cursor.execute('''
            SELECT DISTINCT DATE(start_date) as training_date 
            FROM workout_sessions 
            WHERE user_id = ?
            ORDER BY training_date DESC
            LIMIT 30
        ''', (message.from_user.id,)).fetchall()
        
        if not dates:
            await message.answer("Нет данных о тренировках")
            return
        
        keyboard = InlineKeyboardMarkup(row_width=1)
        for date in dates:
            if not date[0]:  # Проверка на пустые значения
                continue
            
            try:
                # Преобразуем дату
                date_str = datetime.strptime(date[0], '%Y-%m-%d').strftime('%d.%m.%Y')
                keyboard.add(InlineKeyboardButton(date_str, callback_data=f"stats_date_{date[0]}"))
            except Exception as e:
                logging.error(f"Ошибка обработки даты {date[0]}: {e}")
                continue
        
        await message.answer("Выберите дату:", reply_markup=keyboard)
    
    except Exception as e:
        logging.error(f"Ошибка в show_date_stats: {e}")
        await message.answer("⚠️ Ошибка при загрузке статистики")

@dp.callback_query_handler(lambda c: c.data.startswith('stats_date_'))
async def process_stats_date(callback: types.CallbackQuery):
    try:
        date = callback.data.split('_')[2]
        
        # Валидация формата даты
        try:
            parsed_date = datetime.strptime(date, '%Y-%m-%d')
        except ValueError as e:
            logging.error(f"Неверный формат даты: {date} - {str(e)}")
            await callback.answer("❌ Ошибка формата даты")
            return

        # Запрос к базе с обработкой ошибок
        try:
            sessions = cursor.execute('''
                SELECT 
                    ws.session_id,
                    ws.start_date,
                    ws.end_date,
                    COUNT(DISTINCT wr.exercise_id) as exercises_count
                FROM workout_sessions ws
                LEFT JOIN workout_results wr ON ws.session_id = wr.workout_session_id
                WHERE ws.user_id = ? AND DATE(ws.start_date) = ?
                GROUP BY ws.session_id
                ORDER BY ws.start_date DESC
            ''', (callback.from_user.id, date)).fetchall()
        except sqlite3.OperationalError as e:
            logging.error(f"SQL ошибка: {str(e)}")
            await callback.answer("⚠️ Ошибка базы данных")
            return

        if not sessions:
            await callback.message.edit_text("🏋️‍♂️ Тренировок за этот день не найдено")
            return
        
        text = f"📅 *Тренировки за {parsed_date.strftime('%d.%m.%Y')}:*\n\n"
        
        for i, (session_id, start, end, ex_count) in enumerate(sessions, 1):
            # Пропуск записей с неполными данными
            if not all([session_id, start, end]):
                continue
                
            try:
                start_dt = datetime.strptime(start, "%Y-%m-%d %H:%M:%S.%f")
                end_dt = datetime.strptime(end, "%Y-%m-%d %H:%M:%S.%f")
                duration = end_dt - start_dt
                
                # Получение количества подходов
                sets_count = cursor.execute(
                    'SELECT COUNT(*) FROM workout_results WHERE workout_session_id = ?',
                    (session_id,)
                ).fetchone()[0]
                
                text += (
                    f"🏋️ *Тренировка #{i}*\n"
                    f"▫️ Время: {start_dt.strftime('%H:%M')} - {end_dt.strftime('%H:%M')}\n"
                    f"▫️ Длительность: {duration.seconds//3600}ч {(duration.seconds//60)%60}м\n"
                    f"▫️ Упражнений: {ex_count}\n"
                    f"▫️ Подходов: {sets_count}\n\n"
                )
                
            except Exception as e:
                logging.error(f"Ошибка обработки сессии {session_id}: {str(e)}")

        # Добавляем кнопку только если есть данные
        if len(text) > 10:
            keyboard = InlineKeyboardMarkup()
            keyboard.add(InlineKeyboardButton("🔍 Детализация", callback_data=f"full_stats_{date}"))
            await callback.message.edit_text(text, reply_markup=keyboard, parse_mode=ParseMode.MARKDOWN)
        else:
            await callback.message.edit_text("😕 Нет данных для отображения")

    except Exception as e:
        logging.error(f"Критическая ошибка: {str(e)}")
        await callback.answer("⚠️ Системная ошибка")

@dp.callback_query_handler(lambda c: c.data.startswith('full_stats_'))
async def show_full_stats(callback: types.CallbackQuery):
    try:
        date = callback.data.split('_')[2]
        
        results = cursor.execute('''
            SELECT 
                e.name as exercise_name,
                wr.sets,
                wr.reps,
                wr.weight,
                w.name as workout_name,
                ws.start_date
            FROM workout_sessions ws
            JOIN workout_results wr ON ws.session_id = wr.workout_session_id
            JOIN exercises e ON wr.exercise_id = e.id
            JOIN workouts w ON wr.workout_id = w.id
            WHERE ws.user_id = ? AND DATE(ws.start_date) = ?
            ORDER BY ws.start_date DESC, e.name, wr.sets
        ''', (callback.from_user.id, date)).fetchall()

        if not results:
            await callback.answer("Нет данных за этот день")
            return

        text = f"📊 *Детальная статистика за {datetime.strptime(date, '%Y-%m-%d').strftime('%d.%m.%Y')}:*\n\n"
        current_workout = None
        exercises = defaultdict(list)
        
        # Группируем подходы по упражнениям
        for ex_name, sets, reps, weight, workout_name, start in results:
            exercises[ex_name].append((sets, reps, weight))
            current_workout = workout_name

        # Формируем вывод
        if current_workout:
            text += f"🏋️‍♂️ {current_workout}\n"
            
        for ex_name, sets_list in exercises.items():
            text += f"\n{ex_name.capitalize()}\n"
            for set_num, reps, weight in sorted(sets_list, key=lambda x: x[0]):
                weight_str = f" (вес: {weight} кг)" if weight and weight > 0 else ""
                text += f"▫️ подход {set_num}: {reps} повторений{weight_str}\n"

        await callback.message.edit_text(text, parse_mode=ParseMode.MARKDOWN)

    except Exception as e:
        logging.error(f"Ошибка в show_full_stats: {str(e)}")
        await callback.answer("⚠️ Ошибка загрузки детальной статистики")

@dp.message_handler(lambda message: message.text == "📊 Прогресс", state='*')
async def show_progress(message: types.Message):
    try:
        # Общая статистика
        total_stats = cursor.execute('''
            SELECT 
                COUNT(DISTINCT ws.session_id) as total_workouts,
                COUNT(DISTINCT wr.exercise_id) as total_exercises,
                SUM(wr.reps) as total_reps,
                AVG(wr.weight) as avg_weight
            FROM workout_sessions ws
            LEFT JOIN workout_results wr ON ws.session_id = wr.workout_session_id
            WHERE ws.user_id = ?
        ''', (message.from_user.id,)).fetchone()

        # Статистика за последние 7 дней
        weekly_stats = cursor.execute('''
            SELECT 
                COUNT(DISTINCT ws.session_id) as weekly_workouts,
                DATE(ws.start_date) as day
            FROM workout_sessions ws
            WHERE ws.user_id = ? AND ws.start_date >= DATE('now', '-7 days')
            GROUP BY day
        ''', (message.from_user.id,)).fetchall()

        # Самые популярные упражнения
        top_exercises = cursor.execute('''
            SELECT 
                e.name,
                COUNT(wr.id) as total_sets
            FROM workout_results wr
            JOIN exercises e ON wr.exercise_id = e.id
            WHERE wr.user_id = ?
            GROUP BY e.name
            ORDER BY total_sets DESC
            LIMIT 5
        ''', (message.from_user.id,)).fetchall()

        # Формирование отчета
        report = [
            "🏆 *Ваша статистика:*",
            f"▫️ Всего тренировок: {total_stats[0] or 0}",
            f"▫️ Уникальных упражнений: {total_stats[1] or 0}",
            f"▫️ Общее количество повторов: {total_stats[2] or 0}",
            f"▫️ Средний рабочий вес: {total_stats[3] or 0:.1f} кг\n",
            "📅 *Активность за неделю:*"
        ]

        # Добавляем график активности
        russian_days = ['Пн', 'Вт', 'Ср', 'Чт', 'Пт', 'Сб', 'Вс']
        week_days = {day: 0 for day in russian_days}  # Инициализация нулями

        for day_entry in weekly_stats:
            date_str = day_entry[1]
            try:
                date_obj = datetime.strptime(date_str, '%Y-%m-%d')
                day_index = date_obj.weekday()  # 0 = Пн, 6 = Вс
                day_name = russian_days[day_index]
                week_days[day_name] = day_entry[0]
            except Exception as e:
                logging.error(f"Ошибка обработки даты {date_str}: {e}")

        # Формируем график для всех дней
        for day in russian_days:
            count = week_days.get(day, 0)
            bar_count = min(count, 5)  # Ограничиваем до 5 блоков
            bars = '▰' * bar_count + '▱' * (5 - bar_count)
            report.append(f"{day}: {bars}")

        # Топ упражнений
        report.extend([
            "\n🔥 *Топ упражнений:*",
            *[f"{i+1}. {ex[0]} - {ex[1]} подходов" for i, ex in enumerate(top_exercises)]
        ])

        # Отправка сообщения
        await message.answer("\n".join(report), parse_mode=ParseMode.MARKDOWN)

        # Кнопка для детальной статистики
        keyboard = InlineKeyboardMarkup()
        keyboard.add(InlineKeyboardButton("📈 Подробный прогресс", callback_data="full_progress"))
        await message.answer("Хотите увидеть больше статистики?", reply_markup=keyboard)

    except Exception as e:
        logging.error(f"Ошибка в show_progress: {e}")
        await message.answer("⚠️ Не удалось загрузить статистику")

@dp.callback_query_handler(lambda c: c.data == "full_progress")
async def show_full_progress(callback: types.CallbackQuery):
    try:
        # Статистика по максимальным весам
        max_weights = cursor.execute('''
            SELECT 
                e.name,
                MAX(wr.weight) as max_weight
            FROM workout_results wr
            JOIN exercises e ON wr.exercise_id = e.id
            WHERE wr.user_id = ?
            GROUP BY e.name
            ORDER BY max_weight DESC
            LIMIT 5
        ''', (callback.from_user.id,)).fetchall()

        # Статистика по прогрессу
        progress = cursor.execute('''
            SELECT 
                e.name,
                wr.weight,
                DATE(wr.end_date)
            FROM workout_results wr
            JOIN exercises e ON wr.exercise_id = e.id
            WHERE wr.user_id = ? AND wr.weight IS NOT NULL
            ORDER BY wr.end_date
        ''', (callback.from_user.id,)).fetchall()

        # Формирование отчета
        report = [
            "🏅 *Рекорды:*",
            *[f"▫️ {ex[0]}: {ex[1]} кг" for ex in max_weights if ex[1]],
            "\n📈 *Прогресс весов:*"
        ]

        # Группировка по упражнениям
        progress_data = {}
        for ex in progress:
            if ex[0] not in progress_data:
                progress_data[ex[0]] = []
            progress_data[ex[0]].append((ex[2], ex[1]))

        # Добавление прогресса
        for ex, data in progress_data.items():
            report.append(f"\n➤ {ex}:")
            report.extend([f"{date}: {weight} кг" for date, weight in data[-3:]])  # Последние 3 записи

        await callback.message.answer("\n".join(report), parse_mode=ParseMode.MARKDOWN)

    except Exception as e:
        logging.error(f"Ошибка в full_progress: {e}")
        await callback.answer("⚠️ Ошибка загрузки данных")


########## График веса

# Функция для построения графика веса
async def plot_weight_graph(dates, weights, chat_id):
    plt.style.use("cyberpunk")  # Применение стиля из библиотеки mplcyberpunk
    plt.figure(figsize=(10, 6))

    plt.plot(dates, weights, marker='o', label='Вес')

    plt.xlabel('Дата')
    plt.ylabel('Вес (кг)')
    plt.title('График изменения веса')
    plt.legend()
    plt.xticks(rotation=45)
    mplcyberpunk.add_glow_effects()  # Добавление светящихся эффектов
    plt.tight_layout()

    with tempfile.NamedTemporaryFile(suffix='.png', delete=False) as tmpfile:
        graph_path = tmpfile.name

    plt.savefig(graph_path)
    plt.close()
    print(f"График сохранен по пути: {graph_path}")

    with open(graph_path, 'rb') as photo:
        await bot.send_photo(chat_id, photo)

    os.remove(graph_path)
    print(f"График удален по пути: {graph_path}")

@dp.message_handler(text="График веса")
async def send_weight_graph(message: types.Message):
    user_id = message.from_user.id
    weights = cursor.execute('SELECT weight, data FROM weights WHERE user_id = ? ORDER BY data DESC', (user_id,)).fetchall()

    if weights:
        dates = []
        weights_list = []
        for weight, data in weights:
            dates.append(datetime.strptime(data, '%d.%m.%Y'))
            weights_list.append(weight)

        # Построение графика
        await plot_weight_graph(dates, weights_list, message.chat.id)
    else:
        await message.answer("📭 У вас пока нет записей веса.")


# Функция для построения графика результатов тренировок

@dp.message_handler(commands=['graph_training'])
async def send_training_graph(message: types.Message):
    user_id = message.from_user.id
    workouts = cursor.execute('SELECT id, name FROM workouts WHERE user_id = ?', (user_id,)).fetchall()

    if workouts:
        keyboard = types.InlineKeyboardMarkup(row_width=1)
        for workout in workouts:
            keyboard.add(types.InlineKeyboardButton(workout[1], callback_data=f"select_workout_graph_{workout[0]}"))
        await message.answer("Выберите тренировку для построения графика:", reply_markup=keyboard)
    else:
        await message.answer("У вас пока нет тренировок.")

# Добавляем клавиатуру для выбора типа графика
def get_graph_type_keyboard(workout_id, exercise_id):
    return InlineKeyboardMarkup(row_width=2).add(
        InlineKeyboardButton("📈 Линейный", callback_data=f"graph_type_{workout_id}_{exercise_id}_line"),
        InlineKeyboardButton("📊 Столбчатый", callback_data=f"graph_type_{workout_id}_{exercise_id}_bar")
    )

# Модифицированная функция построения графиков
async def plot_training_graph(dates, reps, exercise_name, chat_id, graph_type='line'):
    plt.style.use("cyberpunk")
    plt.figure(figsize=(10, 6))

    if graph_type == 'bar':
        # Для столбчатой диаграммы преобразуем даты в текстовый формат
        str_dates = [d.strftime('%d.%m.%Y') for d in dates]
        plt.bar(str_dates, reps, color='#08F7FE', edgecolor='#FE53BB')
    else:
        plt.plot(dates, reps, marker='o', markersize=8, 
                markerfacecolor='#08F7FE', markeredgecolor='#FE53BB',
                linewidth=2, color='#00ff9f')

    plt.xlabel('Дата', fontsize=12)
    plt.ylabel('Повторения', fontsize=12)
    plt.title(f'📊 {exercise_name}', fontsize=14, pad=20, color='#ff00ff')
    plt.xticks(rotation=45)
    
    # Добавляем свечение
    mplcyberpunk.add_glow_effects()
    plt.tight_layout()

    # Сохранение и отправка
    with tempfile.NamedTemporaryFile(suffix='.png', delete=False) as tmpfile:
        plt.savefig(tmpfile.name, bbox_inches='tight', dpi=120)
        plt.close()
        
        async with aiofiles.open(tmpfile.name, 'rb') as photo:
            await bot.send_photo(chat_id, photo)
    
    os.unlink(tmpfile.name)

# Модифицированный обработчик тренировок
@dp.callback_query_handler(lambda c: c.data.startswith('select_workout_graph_'))
async def process_workout_graph_selection(callback_query: types.CallbackQuery):
    workout_id = int(callback_query.data.split('_')[3])
    exercises = cursor.execute('SELECT id, name FROM exercises WHERE workout_id = ?', (workout_id,)).fetchall()

    if not exercises:
        await bot.send_message(callback_query.from_user.id, "Нет упражнений в этой тренировке.")
        return

    keyboard = InlineKeyboardMarkup(row_width=1)
    for exercise in exercises:
        btn_text = f"🏋️ {exercise[1]}"
        callback_data = f"select_exercise_graph_{workout_id}_{exercise[0]}"
        keyboard.add(InlineKeyboardButton(btn_text, callback_data=callback_data))
    
    await bot.send_message(
        callback_query.from_user.id,
        "Выберите упражнение для анализа:",
        reply_markup=keyboard
    )

# Новый обработчик выбора упражнения
@dp.callback_query_handler(lambda c: c.data.startswith('select_exercise_graph_'))
async def process_exercise_selection(callback_query: types.CallbackQuery):
    _, _, _, workout_id, exercise_id = callback_query.data.split('_')
    workout_id = int(workout_id)
    exercise_id = int(exercise_id)
    
    await bot.send_message(
        callback_query.from_user.id,
        "Выберите тип графика:",
        reply_markup=get_graph_type_keyboard(workout_id, exercise_id)
    )

# Обработчик выбора типа графика
@dp.callback_query_handler(lambda c: c.data.startswith('graph_type_'))
async def process_graph_type_selection(callback_query: types.CallbackQuery):
    _, _, workout_id, exercise_id, graph_type = callback_query.data.split('_')
    workout_id = int(workout_id)
    exercise_id = int(exercise_id)
    
    # Получаем данные упражнения
    exercise = cursor.execute('SELECT name FROM exercises WHERE id = ?', (exercise_id,)).fetchone()
    results = cursor.execute('''
        SELECT end_date, reps 
        FROM workout_results 
        WHERE user_id = ? AND workout_id = ? AND exercise_id = ?
        ORDER BY end_date
    ''', (callback_query.from_user.id, workout_id, exercise_id)).fetchall()
    
    if not results:
        await bot.send_message(callback_query.from_user.id, "Нет данных для этого упражнения.")
        return
    
    dates = [datetime.strptime(r[0], '%Y-%m-%d %H:%M:%S') for r in results]
    reps = [r[1] for r in results]
    
    await plot_training_graph(
        dates=dates,
        reps=reps,
        exercise_name=exercise[0],
        chat_id=callback_query.from_user.id,
        graph_type=graph_type
    )

##### Крутой рассчет калорий

# Функция для создания изображения с результатами калькулятора калорий и шкалой ИМТ
async def create_calorie_image(chat_id, maintenance_calories, protein, fat, carbs, bmi):
    # Создание изображения  первое ширина второе высота
    img = Image.new('RGB', (770, 730), color=(50, 50, 50))  # Темный фон
    draw = ImageDraw.Draw(img)

    # Загрузка шрифта (убедитесь, что у вас есть файл шрифта "dejavusans.ttf" в той же директории)
    try:
        font_title = ImageFont.truetype("dejavusans.ttf", 30)
        font_text = ImageFont.truetype("dejavusans.ttf", 24)
        font_bmi = ImageFont.truetype("dejavusans.ttf", 20)
    except IOError:
        font_title = ImageFont.load_default()
        font_text = ImageFont.load_default()
        font_bmi = ImageFont.load_default()

    # Добавление текста на изображение
    draw.text((30, 30), "Ваша суточная норма калорий", font=font_title, fill=(255, 255, 255))
    draw.text((30, 90), f"{int(maintenance_calories)} кКал*", font=font_title, fill=(255, 255, 255))
    draw.text((30, 170), "Из которых:", font=font_text, fill=(255, 255, 255))

    # Добавление данных о макронутриентах
    
    draw.text((30, 230), f"- {protein:.2f} г белки", font=font_text, fill=(255, 255, 0))
    draw.text((30, 290), f"- {fat:.2f} г жиры", font=font_text, fill=(255, 0, 0))
    draw.text((30, 350), f"- {carbs:.2f} г углеводы", font=font_text, fill=(255, 182, 193))

    # Добавление примечания
    draw.text((30, 430), "* Данные результаты являются рекомендацией, \nдля более точных результов обратитесь к специалисту.", font=font_text, fill=(255, 255, 255))

    # Добавление шкалы ИМТ
    draw.text((30, 500), "Ваш индекс массы тела", font=font_title, fill=(255, 255, 255))
    draw.text((30, 560), f"{bmi:.1f}", font=font_title, fill=(255, 255, 255))

    # Рисование шкалы ИМТ
    scale_height = 30
    scale_width = 715
    scale_x = 30
    scale_y = 600
    
    # Градиентная шкала
    for i in range(scale_width):
        r = int(255 * (i / scale_width))
        g = int(255 * (1 - (i / scale_width)))
        draw.line([(scale_x + i, scale_y), (scale_x + i, scale_y + scale_height)], fill=(r, g, 0))
    
    # Метки на шкале
    draw.text((scale_x - 5, scale_y + scale_height + 10), "Дефицит", font=font_bmi, fill=(255, 255, 255))
    draw.text((scale_x + scale_width // 2 - 30, scale_y + scale_height + 10), "Норма", font=font_bmi, fill=(255, 255, 255))
    draw.text((scale_x + scale_width - 85, scale_y + scale_height + 10), "Избыток", font=font_bmi, fill=(255, 255, 255))

    # Позиция на шкале
    bmi_position = int((bmi - 18.5) / (30 - 18.5) * scale_width)
    draw.ellipse([(scale_x + bmi_position - 5, scale_y - 5), (scale_x + bmi_position + 5, scale_y + 5)], fill=(255, 255, 255))

    # Сохранение изображения во временный файл
    with tempfile.NamedTemporaryFile(suffix='.png', delete=False) as tmpfile:
        image_path = tmpfile.name

    img.save(image_path)
    print(f"Изображение сохранено по пути: {image_path}")

    # Отправка изображения пользователю
    with open(image_path, 'rb') as photo:
        await bot.send_photo(chat_id, photo)

    os.remove(image_path)
    print(f"Изображение удалено по пути: {image_path}")

# Функция для расчета калорий и макронутриентов
async def calculate_calories(chat_id, state: FSMContext):
    data = await state.get_data()
    height = data['height']
    weight = data['weight']
    gender = data['gender']
    age = data['age']
    activity_level = data['activity_level']

    if gender == 'Мужской':
        bmr = 10 * weight + 6.25 * height - 5 * age + 5
    else:
        bmr = 10 * weight + 6.25 * height - 5 * age - 161

    maintenance_calories = bmr * activity_level

    # Расчет макронутриентов (пример: 20% белки, 30% жиры, 50% углеводы)
    protein = maintenance_calories * 0.2 / 4
    fat = maintenance_calories * 0.3 / 9
    carbs = maintenance_calories * 0.5 / 4

    # Расчет ИМТ
    bmi = weight / ((height / 100) ** 2)

    await create_calorie_image(chat_id, maintenance_calories, protein, fat, carbs, bmi)

    # Создаем клавиатуру с кнопками
    menu_markup = ReplyKeyboardMarkup(
        resize_keyboard=True,
        one_time_keyboard=True,
        row_width=1
    ).add(
        KeyboardButton('Питание'),
        KeyboardButton('🏠 Главное меню')
    )
    
    # Отправляем сообщение с клавиатурой
    await bot.send_message(
        chat_id,
        "Выберите действие:",
        reply_markup=menu_markup
    )

    await state.finish()

@dp.message_handler(text="Калькулятор калорий")
async def start_calories(message: types.Message):
    await CalorieStates.waiting_for_height.set()
    await message.answer(
        "📏 Введите ваш рост (в сантиметрах):", 
        reply_markup=types.ReplyKeyboardRemove()  # Убираем клавиатуру для ввода числа
    )

@dp.message_handler(state=CalorieStates.waiting_for_height)
async def process_height(message: types.Message, state: FSMContext):
    try:
        height = int(message.text)
        await state.update_data(height=height)
        await CalorieStates.waiting_for_weight.set()
        await message.answer("Введите ваш вес (кг):")
    except ValueError:
        await message.answer("Пожалуйста, введите корректное значение роста (см):")

@dp.message_handler(state=CalorieStates.waiting_for_weight)
async def process_weight(message: types.Message, state: FSMContext):
    try:
        weight = int(message.text)
        await state.update_data(weight=weight)
        markup = types.ReplyKeyboardMarkup(resize_keyboard=True, one_time_keyboard=True)
        markup.add('Мужской', 'Женский')
        await CalorieStates.waiting_for_gender.set()
        await message.answer("Выберите ваш пол:", reply_markup=markup)
    except ValueError:
        await message.answer("Пожалуйста, введите корректное значение веса (кг):")

@dp.message_handler(state=CalorieStates.waiting_for_gender)
async def process_gender(message: types.Message, state: FSMContext):
    gender = message.text
    if gender in ['Мужской', 'Женский']:
        await state.update_data(gender=gender)
        await CalorieStates.waiting_for_age.set()
        await message.answer("Введите ваш возраст (лет):")
    else:
        await message.answer("Пожалуйста, выберите пол из предложенных вариантов.")

@dp.message_handler(state=CalorieStates.waiting_for_age)
async def process_age(message: types.Message, state: FSMContext):
    try:
        age = int(message.text)
        await state.update_data(age=age)
        markup = types.ReplyKeyboardMarkup(one_time_keyboard=True)
        for activity in activity_levels.keys():
            markup.add(activity)
        await CalorieStates.waiting_for_activity_level.set()
        await message.answer("Выберите степень вашей физической активности:", reply_markup=markup)
    except ValueError:
        await message.answer("Пожалуйста, введите корректное значение возраста (лет):")

@dp.message_handler(state=CalorieStates.waiting_for_activity_level)
async def process_activity_level(message: types.Message, state: FSMContext):
    activity_level = message.text
    if activity_level in activity_levels:
        await state.update_data(activity_level=activity_levels[activity_level])
        await calculate_calories(message.from_user.id, state)
    else:
        await message.answer("Пожалуйста, выберите степень физической активности из предложенных вариантов.")

######### Замеры тела

# Обработчик для запуска замера тела
@dp.message_handler(text="Замерить тело")
async def start_body_measurement(message: types.Message):
    await BodyMeasurementStates.waiting_for_weight.set()
    await message.answer("⚖️ Введите ваш вес (в килограммах):")

@dp.message_handler(state=BodyMeasurementStates.waiting_for_weight)
async def process_weight(message: types.Message, state: FSMContext):
    try:
        weight = float(message.text)
        await state.update_data(weight=weight)
        await BodyMeasurementStates.waiting_for_height.set()
        await message.answer("Введите ваш рост (см):")
    except ValueError:
        await message.answer("Пожалуйста, введите корректное значение веса (кг):")

@dp.message_handler(state=BodyMeasurementStates.waiting_for_height)
async def process_height(message: types.Message, state: FSMContext):
    try:
        height = float(message.text)
        await state.update_data(height=height)
        await BodyMeasurementStates.waiting_for_waist.set()
        await message.answer("Введите обхват талии (см):")
    except ValueError:
        await message.answer("Пожалуйста, введите корректное значение роста (см):")

@dp.message_handler(state=BodyMeasurementStates.waiting_for_waist)
async def process_waist(message: types.Message, state: FSMContext):
    try:
        waist = float(message.text)
        await state.update_data(waist=waist)
        await BodyMeasurementStates.waiting_for_hips.set()
        await message.answer("Введите обхват бедер (см):")
    except ValueError:
        await message.answer("Пожалуйста, введите корректное значение обхвата талии (см):")

@dp.message_handler(state=BodyMeasurementStates.waiting_for_hips)
async def process_hips(message: types.Message, state: FSMContext):
    try:
        hips = float(message.text)
        await state.update_data(hips=hips)
        await BodyMeasurementStates.waiting_for_chest.set()
        await message.answer("Введите обхват груди (см):")
    except ValueError:
        await message.answer("Пожалуйста, введите корректное значение обхвата бедер (см):")

@dp.message_handler(state=BodyMeasurementStates.waiting_for_chest)
async def process_chest(message: types.Message, state: FSMContext):
    try:
        chest = float(message.text)
        await state.update_data(chest=chest)
        await BodyMeasurementStates.waiting_for_biceps.set()
        await message.answer("Введите обхват бицепса (см):")
    except ValueError:
        await message.answer("Пожалуйста, введите корректное значение обхвата груди (см):")

@dp.message_handler(state=BodyMeasurementStates.waiting_for_biceps)
async def process_biceps(message: types.Message, state: FSMContext):
    try:
        biceps = float(message.text)
        await state.update_data(biceps=biceps)
        await BodyMeasurementStates.waiting_for_thigh.set()
        await message.answer("Введите обхват бедра (см):")
    except ValueError:
        await message.answer("Пожалуйста, введите корректное значение обхвата бицепса (см):")

@dp.message_handler(state=BodyMeasurementStates.waiting_for_thigh)
async def process_thigh(message: types.Message, state: FSMContext):
    try:
        thigh = float(message.text)
        await state.update_data(thigh=thigh)
        await BodyMeasurementStates.waiting_for_photo.set()
        await message.answer("Загрузите фотографию:")
    except ValueError:
        await message.answer("Пожалуйста, введите корректное значение обхвата бедра (см):")

@dp.message_handler(content_types=types.ContentType.PHOTO, state=BodyMeasurementStates.waiting_for_photo)
async def process_photo(message: types.Message, state: FSMContext):
    photo = message.photo[-1]
    file_info = await photo.get_file()
    destination = f"zamery/{message.from_user.id}"
    if not os.path.exists(destination):
        os.makedirs(destination)

    # Найти количество существующих фотографий
    existing_photos = [f for f in os.listdir(destination) if os.path.isfile(os.path.join(destination, f))]
    photo_number = len(existing_photos) + 1

    new_photo_path = os.path.join(destination, f"{photo_number}.jpg")
    await file_info.download(destination_file=new_photo_path)

    data = await state.get_data()
    user_id = message.from_user.id
    current_date = datetime.now().strftime('%d.%m.%Y')

    cursor.execute('''
    INSERT INTO body_measurements (user_id, data, weight, height, waist, hips, chest, biceps, thigh, photo)
    VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
    ''', (user_id, current_date, data['weight'], data['height'], data['waist'], data['hips'], data['chest'], data['biceps'], data['thigh'], new_photo_path))
    conn.commit()

    await message.answer("Данные замера тела и фотография сохранены.")
    await state.finish()

# Обработчик команды для просмотра замеров тела
@dp.message_handler(text="Просмотр замеров")
async def view_body_measurements(message: types.Message):
    user_id = message.from_user.id
    dates = cursor.execute('SELECT DISTINCT data FROM body_measurements WHERE user_id = ? ORDER BY data DESC', (user_id,)).fetchall()

    if dates:
        keyboard = types.InlineKeyboardMarkup(row_width=1)
        for date in dates:
            formatted_date = date[0]
            keyboard.add(types.InlineKeyboardButton(formatted_date, callback_data=f"view_measurement_{formatted_date}"))
        await message.answer("📅 Выберите дату:", reply_markup=keyboard)
    else:
        await message.answer("📭 У вас пока нет замеров тела.")

@dp.callback_query_handler(lambda c: c.data.startswith('view_measurement_'))
async def view_measurement(callback_query: types.CallbackQuery):
    date = callback_query.data.split('_')[2]
    user_id = callback_query.from_user.id
    measurement = cursor.execute('SELECT * FROM body_measurements WHERE user_id = ? AND data = ?', (user_id, date)).fetchone()

    if measurement:
        _, _, weight, height, waist, hips, chest, biceps, thigh, photo_path = measurement

        with open(photo_path, 'rb') as photo:
            await bot.send_photo(callback_query.from_user.id, photo, caption=(
                f"Дата: {date}\n"
                f"Вес: {weight} кг\n"
                f"Рост: {height} см\n"
                f"Талия: {waist} см\n"
                f"Бедра: {hips} см\n"
                f"Грудь: {chest} см\n"
                f"Бицепс: {biceps} см\n"
                f"Бедро: {thigh} см"
            ))
    else:
        await bot.send_message(callback_query.from_user.id, "Замеры тела для этой даты не найдены.")

#  Полноценное самоудаление пользователя из телеграм бота
# Новый обработчик команды
@dp.message_handler(text="Удалить все данные")
async def delete_user_data_command(message: types.Message):
    warning_text = (
        "⚠️ *ВНИМАНИЕ!* Вы собираетесь удалить:\n\n"
        "• Все записи о весе\n"
        "• Созданные тренировки\n"
        "• Результаты тренировок\n"
        "• Замеры тела\n\n"
        "❗ Это действие *НЕЛЬЗЯ ОТМЕНИТЬ!*"
    )

    markup = InlineKeyboardMarkup()
    markup.row(
        InlineKeyboardButton("🗑️ Да, удалить всё", callback_data="confirm_delete"),
        InlineKeyboardButton("🚫 Отмена", callback_data="cancel_delete")
    )
    
    await message.answer(
        warning_text,
        parse_mode=ParseMode.MARKDOWN,
        reply_markup=markup
    )
    await DeleteStates.confirm_deletion.set()

# Обработчик подтверждения удаления
@dp.callback_query_handler(lambda c: c.data == 'confirm_delete', state=DeleteStates.confirm_deletion)
async def process_confirm_delete(callback: types.CallbackQuery):
    user_id = callback.from_user.id
    
    try:
        cursor.execute("BEGIN TRANSACTION;")
        
        # Уточненные запросы для каждой таблицы
        delete_operations = [
            ("DELETE FROM achievements WHERE user_id = ?", (user_id,)),
            ("DELETE FROM current_goals WHERE user_id = ?", (user_id,)),
            ("DELETE FROM user_settings WHERE user_id = ?", (user_id,)),
            ("DELETE FROM workout_schedule WHERE user_id = ?", (user_id,)),
            ("DELETE FROM workout_results WHERE user_id = ?", (user_id,)),
            ("DELETE FROM body_measurements WHERE user_id = ?", (user_id,)),
            ("DELETE FROM weights WHERE user_id = ?", (user_id,)),
            ("DELETE FROM exercises WHERE workout_id IN (SELECT id FROM workouts WHERE user_id = ?)", (user_id,)),
            ("DELETE FROM workouts WHERE user_id = ?", (user_id,)),
            ("DELETE FROM users WHERE telegram_id = ?", (user_id,))
        ]
        
        for query, params in delete_operations:
            cursor.execute(query, params)
        
        conn.commit()
        await callback.message.edit_text("✅ Все ваши данные успешно удалены!")
    
    except sqlite3.Error as e:
        conn.rollback()
        logging.error(f"Ошибка базы данных: {e}")
        await callback.message.answer("❌ Произошла ошибка при удалении. Пожалуйста, попробуйте позже.")
    
    await DeleteStates.confirm_deletion.finish()

# Обработчик отмены удаления
@dp.callback_query_handler(lambda c: c.data == 'cancel_delete', state=DeleteStates.confirm_deletion)
async def process_cancel_delete(callback: types.CallbackQuery):
    await callback.message.edit_text("❌ Удаление отменено.")
    await DeleteStates.confirm_deletion.finish()

#####################################  AI

# Создаем клавиатуру
nutrition_keyboard = ReplyKeyboardMarkup(
    resize_keyboard=True,
    one_time_keyboard=False
).add(KeyboardButton("Остановить диалог"))

@dp.message_handler(text="AI помощник", state='*')
async def start_ai_nutrition(message: types.Message, state: FSMContext):
    # Сбрасываем предыдущее состояние
    await state.finish()
    
    await message.answer(
        "🍎 *Привет, я твой советник по питанию*\n\n"
        "Задай любой вопрос о:\n"
        "- Составлении рациона\n- Подборе диеты\n- Нутриентах\n"
        "➖➖➖➖➖➖➖\n"
        "Чтобы остановить диалог - нажми кнопку ниже 👇",
        parse_mode=ParseMode.MARKDOWN,
        reply_markup=nutrition_keyboard  # Клавиатура с кнопкой "Остановить диалог"
    )
    await NutritionStates.waiting_for_question.set()

@dp.message_handler(lambda message: message.text == "Остановить диалог", state="*")
async def cancel_nutrition_chat(message: types.Message, state: FSMContext):
    # Создаем клавиатуру с кнопками в столбик
    post_nutrition_keyboard = ReplyKeyboardMarkup(
        resize_keyboard=True,
        one_time_keyboard=False,
        keyboard=[
            [KeyboardButton("Питание")],       # Первая строка
            [KeyboardButton("🏠 Главное меню")] # Вторая строка
        ]
    )
    
    await message.answer(
        "Диалог с советником завершен 🍏",
        reply_markup=post_nutrition_keyboard
    )
    await state.finish()

@dp.message_handler(state=NutritionStates.waiting_for_question)
async def handle_nutrition_question(message: types.Message, state: FSMContext):
    try:
        if message.text == "Остановить диалог":
            await cancel_nutrition_chat(message, state)
            return
        # Показываем индикатор набора сообщения
        await types.ChatActions.typing()

        # Создаем клиента OpenAI
        client = OpenAI(
            base_url="https://openrouter.ai/api/v1",
            api_key="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",  # Замените на ваш ключ
        )

        # Отправляем запрос к нейросети
        completion = client.chat.completions.create(
            model="mistralai/mistral-small-3.1-24b-instruct:free",
            messages=[
                {
                    "role": "system",
                    "content": (
                        "Ты - профессиональный диетолог с 20-летним опытом. "
                        "Давай научно обоснованные рекомендации по питанию. "
                        "Отвечай на русском языке. Избегай сложных терминов. "
                        "Если вопрос не по питанию - вежливо откажись отвечать."
                    )
                },
                {
                    "role": "user",
                    "content": message.text
                }
            ],
            temperature=0.6,
            max_tokens=4000
        )

        # Отправляем ответ пользователю
        response = completion.choices[0].message.content
        # Добавляем информационное сообщение
        full_response = (
            f"{response}\n\n"
            "➖➖➖➖➖➖➖\n"
            "Чтобы остановить общение - нажмите кнопку 'Остановить диалог'"
        )

        await message.answer(
            full_response, 
            parse_mode=ParseMode.MARKDOWN,
            reply_markup=nutrition_keyboard
        )

    except Exception as e:
        await message.answer(
            "⚠️ Ошибка. Попробуйте задать вопрос еще раз или нажмите 'Остановить диалог'",
            reply_markup=nutrition_keyboard
        )

# Функция для остановки бота
async def on_shutdown(dp):
    logging.warning('Shutting down..')
    await bot.delete_webhook()
    await dp.storage.close()
    await dp.storage.wait_closed()
    scheduler.shutdown()

# Функция для запуска бота
async def on_startup(dp):
    try:
        await bot.set_webhook(f"{BASE_WEBHOOK_URL}{WEBHOOK_PATH}", secret_token=WEBHOOK_SECRET)
        # Запланировать выполнение функций
        
        # Проверяем каждую минуту
        scheduler.add_job(
        check_reminders,
        'cron',
        minute='*',
        timezone='Europe/Moscow'
    )
        scheduler.start()
    except Exception as e:
        logging.error(f"Error in on_startup: {e}")

if __name__ == '__main__':
    logging.basicConfig(
        level=logging.INFO,
        format='%(asctime)s - %(name)s - %(levelname)s - %(message)s'
    )
    
    # Дополнительная настройка для APScheduler
    logging.getLogger('apscheduler').setLevel(logging.WARNING)
    
    from aiogram import executor
    executor.start_webhook(
        dispatcher=dp,
        webhook_path=WEBHOOK_PATH,
        on_startup=on_startup,
        on_shutdown=on_shutdown,
        skip_updates=True,
        host=WEB_SERVER_HOST,
        port=WEB_SERVER_PORT,
    )

