from datetime import datetime, timedelta, timezone
from telegram import InlineKeyboardButton, InlineKeyboardMarkup, Update
from telegram.ext import ContextTypes
from asgiref.sync import sync_to_async
from hotels.models import Reservation, Hotel
from users.models import User

from bot.utils.pdf_report import generate_pdf_report
from bot.utils.database import get_hotels_for_user, get_hotel_by_name
from datetime import datetime
from django.utils.timezone import make_aware, is_aware, is_naive
import os
import traceback


async def statistics(update: Update, context: ContextTypes.DEFAULT_TYPE):
    """Вывод списка отелей для статистики."""
    query = update.callback_query
    user_id = query.from_user.id
    await query.answer()

    # Получаем пользователя
    user = await sync_to_async(User.objects.filter(chat_id=user_id).first)()
    if not user:
        await query.edit_message_text("Вы не зарегистрированы в системе.")
        return

    # Получаем отели, связанные с пользователем
    user_hotels = await get_hotels_for_user(user)
    if not user_hotels:
        await query.edit_message_text("У вас нет доступных отелей для статистики.")
        return

    # Формируем кнопки для выбора отеля
    keyboard = [
        [InlineKeyboardButton(hotel.hotel.name, callback_data=f"stats_hotel_{hotel.hotel.id}")]
        for hotel in user_hotels
    ]
    keyboard.append([InlineKeyboardButton("🏠 Главная", callback_data="main_menu")])
    reply_markup = InlineKeyboardMarkup(keyboard)
    await query.edit_message_text("Выберите отель:", reply_markup=reply_markup)

async def stats_select_period(update: Update, context: ContextTypes.DEFAULT_TYPE):
    """Выбор периода времени для статистики."""
    query = update.callback_query
    await query.answer()

    hotel_id = int(query.data.split("_")[2])
    context.user_data["selected_hotel"] = hotel_id

    keyboard = [
        [InlineKeyboardButton("День", callback_data="stats_period_day")],
        [InlineKeyboardButton("Неделя", callback_data="stats_period_week")],
        [InlineKeyboardButton("Месяц", callback_data="stats_period_month")],
        [InlineKeyboardButton("Все время", callback_data="stats_period_all")],
        [InlineKeyboardButton("🏠 Главная", callback_data="main_menu")],
        [InlineKeyboardButton("🔙 Назад", callback_data="statistics")],
    ]
    reply_markup = InlineKeyboardMarkup(keyboard)
    await query.edit_message_text("Выберите период времени:", reply_markup=reply_markup)
    
    
def ensure_datetime(value):
    # print(f"statistics.py [DEBUG] ensure_datetime: Received value: {value} ({type(value)})")
    """
    Ensure that the given value is a timezone-aware datetime object.

    If the given value is a string, it is assumed to be in the format
    '%Y-%m-%d %H:%M:%S'. If the given value is a naive datetime object,
    it is converted to a timezone-aware datetime object using
    django.utils.timezone.make_aware.

    :param value: The value to be converted
    :type value: str or datetime
    :return: A timezone-aware datetime object
    :rtype: datetime
    """
    if isinstance(value, str):
        value = datetime.strptime(value, '%Y-%m-%d %H:%M:%S')
    if isinstance(value, datetime) and is_naive(value):
        value = make_aware(value)
    # print(f"statistics.py [DEBUG] ensure_datetime: Returning value: {value} ({type(value)})")
    return value


async def generate_statistics(update: Update, context: ContextTypes.DEFAULT_TYPE):
    """Генерация и отправка статистики."""
    query = update.callback_query
    await query.answer()

    try:
        hotel_id = context.user_data.get("selected_hotel")

        if not hotel_id:
            raise ValueError(f"ID отеля не найден в user_data: {context.user_data}")

        period = query.data.split("_")[2]

        
        now = datetime.utcnow().replace(tzinfo=timezone.utc)

        print(type(now))

        print(type(period))

        start_date, end_date = get_period_dates(period, now)


        try:
            # Получаем бронирования
            reservations = await sync_to_async(list)(
                Reservation.objects.filter(
                    hotel_id=hotel_id,
                    check_in__gte=start_date,
                    check_in__lte=end_date
                ).select_related('hotel')
            )


        except Exception as e:
            raise RuntimeError(f"statistics.py Ошибка при выборке бронирований: {e}") from e

        if not reservations:
            await query.edit_message_text("statistics.py Нет данных для статистики за выбранный период.")
            return

        try:
            # Получаем данные об отеле
            hotel = await sync_to_async(Hotel.objects.get)(id=hotel_id)
  
        except Hotel.DoesNotExist:
            raise RuntimeError(f"statistics.py Отель с ID {hotel_id} не найден")
        except Exception as e:
            raise RuntimeError(f"statistics.py Ошибка при выборке отеля: {e}") from e

        try:
            # Генерация отчета
            file_path = await generate_pdf_report(hotel.name, reservations, start_date, end_date)

        except Exception as e:
            raise RuntimeError(f"statistics.py [ERROR] Ошибка при генерации PDF-отчета: {e}") from e

        try:
            # Отправка файла через Telegram
            with open(file_path, "rb") as file:
                await query.message.reply_document(document=file, filename=f"{hotel.name}_report.pdf")

        except Exception as e:
            raise RuntimeError(f"Ошибка при отправке PDF-файла: {e}") from e

        # Удаляем временный файл
        if os.path.exists(file_path):
            os.remove(file_path)
   

    except Exception as e:
        # Логируем стек вызовов для детального анализа
        error_trace = traceback.format_exc()

        await query.edit_message_text(f"Произошла ошибка: {str(e)}")


def get_period_dates(period, now):
    if period == "day":
        start_date = (now - timedelta(days=1)).replace(hour=0, minute=0, second=0, microsecond=0)
        end_date = now.replace(hour=23, minute=59, second=59, microsecond=999999)
    elif period == "week":
        start_date = (now - timedelta(days=7)).replace(hour=0, minute=0, second=0, microsecond=0)
        end_date = now.replace(hour=23, minute=59, second=59, microsecond=999999)
    elif period == "month":
        start_date = (now - timedelta(days=30)).replace(hour=0, minute=0, second=0, microsecond=0)
        end_date = now.replace(hour=23, minute=59, second=59, microsecond=999999)
    elif period == "all":
        start_date = (now - timedelta(days=1500)).replace(hour=0, minute=0, second=0, microsecond=0)
        end_date = now.replace(hour=23, minute=59, second=59, microsecond=999999)
    else:
        start_date = (now - timedelta(days=1500)).replace(hour=0, minute=0, second=0, microsecond=0)
        end_date = now.replace(hour=23, minute=59, second=59, microsecond=999999)
    return start_date, end_date

async def stats_back(update: Update, context):
    """Возврат к выбору отеля."""
    query = update.callback_query
    await query.answer()

    # Получаем отели, связанные с пользователем
    user_id = query.from_user.id
    user = await sync_to_async(User.objects.filter(chat_id=user_id).first)()
    if not user:
        await query.edit_message_text("Ошибка: Пользователь не найден.")
        return

    hotels = await get_hotels_for_user(user)
    if not hotels:
        await query.edit_message_text("У вас нет доступных отелей.")
        return

    # Формируем кнопки для выбора отеля
    keyboard = [
        [InlineKeyboardButton(hotel.name, callback_data=f"stats_hotel_{hotel.id}")]
        for hotel in hotels
    ]
    keyboard.append([InlineKeyboardButton("🏠 Главная", callback_data="main_menu")])
    reply_markup = InlineKeyboardMarkup(keyboard)
    await query.edit_message_text("Выберите отель:", reply_markup=reply_markup)
