# import random
# import logging
# from asgiref.sync import async_to_sync
# from django.contrib import admin, messages
# from django.urls import path, reverse
# from django.shortcuts import render, redirect, get_object_or_404
# from django.utils import timezone
# from django.http import HttpResponseRedirect, HttpResponse
# from django.utils.html import format_html
# from .models import Lottery, Prize, LotteryParticipant, DrawResult
# from .forms import AddParticipantsForm
# from webapp.models import Invoice, Client, BindingRequest
# from bot.notifications import NotificationService
# from bot.utils import create_bot_instance

# # Настройка логгера
# logger = logging.getLogger(__name__)
# logger.setLevel(logging.DEBUG)
# if not logger.handlers:
#     console_handler = logging.StreamHandler()
#     console_handler.setLevel(logging.DEBUG)
#     formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s')
#     console_handler.setFormatter(formatter)
#     logger.addHandler(console_handler)


# def add_participants_view(request):
#     lottery_id = request.GET.get("lottery_id")
#     if not lottery_id:
#         return HttpResponse("Не указан параметр lottery_id", status=400)
#     lottery = get_object_or_404(Lottery, id=lottery_id)

#     used_invoice_ids = LotteryParticipant.objects.filter(lottery=lottery).values_list("invoice_id", flat=True)
#     qs = Invoice.objects.exclude(id__in=used_invoice_ids)

#     deposit_min = request.GET.get("deposit_min")
#     deposit_max = request.GET.get("deposit_max")
#     if deposit_min:
#         qs = qs.filter(deposit_sum__gte=deposit_min)
#     if deposit_max:
#         qs = qs.filter(deposit_sum__lte=deposit_max)

#     if request.method == "POST":
#         form = AddParticipantsForm(request.POST)
#         form.fields["invoices"].queryset = qs
#         if form.is_valid():
#             selected_invoices = form.cleaned_data["invoices"]
#             for invoice in selected_invoices:
#                 LotteryParticipant.objects.create(lottery=lottery, invoice=invoice)
#             messages.success(request, "Участники успешно добавлены.")
#             return redirect("admin:draw_lotteryparticipant_changelist")
#     else:
#         form = AddParticipantsForm()
#         form.fields["invoices"].queryset = qs

#     context = {"form": form, "lottery": lottery}
#     return render(request, "admin/add_participants.html", context)


# def get_client_by_invoice(invoice):
#     """
#     Возвращает клиента, используя значение поля client_club_card_number у счета.
#     Предполагается, что у модели Invoice есть поле client_club_card_number.
#     """
#     try:
#         return Client.objects.get(club_card_number=invoice.client_club_card_number)
#     except Client.DoesNotExist:
#         return None


# def start_draw(request, lottery_id):
#     lottery = get_object_or_404(Lottery, id=lottery_id)
#     logger.info("Запуск розыгрыша для лотереи: %s", lottery.name)

#     notifier = NotificationService(bot=create_bot_instance())
#     # Используем async_to_sync для уведомления о запуске розыгрыша
#     async_to_sync(notifier.notify_draw_start)(lottery)

#     for prize in lottery.prizes.all():
#         logger.info("Обработка приза: %s", prize.prize_place)

#         # Если для приза уже назначен победитель вручную, сохраняем его в таблице результатов
#         if prize.winner:
#             logger.info("Приз '%s' имеет установленного вручную победителя. Сохраняем в таблице результатов.", prize.prize_place)
#             try:
#                 draw_result = lottery.draw_results.get(prize=prize)
#                 draw_result.participant = prize.winner
#                 draw_result.drawn_at = timezone.now()
#                 draw_result.confirmed = False
#                 draw_result.save()
#             except DrawResult.DoesNotExist:
#                 DrawResult.objects.create(
#                     lottery=lottery,
#                     prize=prize,
#                     participant=prize.winner,
#                     confirmed=False,
#                     drawn_at=timezone.now()
#                 )
#             continue

#         try:
#             draw_result = lottery.draw_results.get(prize=prize)
#             if draw_result.confirmed:
#                 logger.info("Приз '%s' уже подтвержден.", prize.prize_place)
#                 continue
#         except DrawResult.DoesNotExist:
#             draw_result = None

#         participants = list(lottery.participants.filter(used=False))
#         logger.info("Найдено свободных участников для приза '%s': %d", prize.prize_place, len(participants))
#         if not participants:
#             logger.warning("Нет свободных участников для приза '%s'.", prize.prize_place)
#             continue

#         winner_participant = random.choice(participants)
#         winner_participant.used = True
#         winner_participant.save()
#         logger.info("Выбран участник с счетом '%s' для приза '%s'.", winner_participant.invoice.api_id, prize.prize_place)

#         if draw_result:
#             draw_result.participant = winner_participant
#             draw_result.drawn_at = timezone.now()
#             draw_result.confirmed = False
#             draw_result.save()
#             logger.info("Обновлен результат розыгрыша для приза '%s'.", prize.prize_place)
#         else:
#             DrawResult.objects.create(
#                 lottery=lottery,
#                 prize=prize,
#                 participant=winner_participant,
#                 confirmed=False,
#                 drawn_at=timezone.now()
#             )
#             logger.info("Создан результат розыгрыша для приза '%s'.", prize.prize_place)

#     draw_results = lottery.draw_results.all()
#     async_to_sync(notifier.notify_draw_results)(lottery, draw_results)
#     return render(request, "admin/draw_result.html", {"lottery": lottery, "draw_results": draw_results})


# def confirm_draw_result(request, result_id):
#     from django.http import HttpResponseRedirect
#     result = get_object_or_404(DrawResult, id=result_id)
#     result.confirmed = True
#     result.save()

#     prize = result.prize
#     prize.winner = result.participant
#     prize.save()

#     logger.info("Подтвержден результат розыгрыша для приза '%s'.", prize.prize_place)
#     messages.success(request, f"Результат для приза '{prize.prize_place}' подтвержден.")

#     # Получаем клиента по счету участника
#     client = get_client_by_invoice(result.participant.invoice)
#     notifier = NotificationService(bot=create_bot_instance())
#     if client:
#         async_to_sync(notifier.notify_prize_status_update)(client, result)

#     return HttpResponseRedirect(reverse("admin:start_draw", args=[result.lottery.id]))


# @admin.register(Lottery)
# class LotteryAdmin(admin.ModelAdmin):
#     list_display = ("name", "description", "created_at", "start_draw_button")
#     search_fields = ("name", "description")

#     def get_urls(self):
#         urls = super().get_urls()
#         custom_urls = [
#             path('<int:lottery_id>/start-draw/', self.admin_site.admin_view(start_draw), name='start_draw'),
#             path('confirm-draw-result/<int:result_id>/', self.admin_site.admin_view(confirm_draw_result), name='confirm_draw_result'),
#         ]
#         return custom_urls + urls

#     def start_draw_button(self, obj):
#         url = reverse("admin:start_draw", args=[obj.pk])
#         return format_html('<a class="btn btn-primary" href="{}">Запуск розыгрыша</a>', url)
#     start_draw_button.short_description = "Розыгрыш"


# @admin.register(Prize)
# class PrizeAdmin(admin.ModelAdmin):
#     list_display = ("lottery", "prize_place", "reward", "winner")
#     list_filter = ("lottery",)
#     search_fields = ("prize_place", "description")


# @admin.register(LotteryParticipant)
# class LotteryParticipantAdmin(admin.ModelAdmin):
#     list_display = ("lottery", "invoice", "added_at", "used")
#     list_filter = ("lottery", "used")
#     search_fields = ("invoice__api_id", "lottery__name")
#     change_list_template = "admin/draw/lotteryparticipant/change_list.html"

#     def changelist_view(self, request, extra_context=None):
#         extra_context = extra_context or {}
#         from draw.models import Lottery
#         active_lotteries = Lottery.objects.filter(prizes__winner__isnull=True).distinct()
#         extra_context['active_lotteries'] = active_lotteries
#         return super().changelist_view(request, extra_context=extra_context)

#     def get_urls(self):
#         from django.urls import path
#         urls = super().get_urls()
#         custom_urls = [
#             path('add-participants/', self.admin_site.admin_view(add_participants_view), name="add_participants"),
#         ]
#         return custom_urls + urls


# @admin.register(DrawResult)
# class DrawResultAdmin(admin.ModelAdmin):
#     list_display = ("lottery", "prize", "participant", "confirmed", "drawn_at")
#     list_filter = ("lottery", "confirmed")
#     search_fields = ("prize__prize_place", "participant__invoice__api_id")

import random
import logging
from asgiref.sync import async_to_sync
from django.contrib import admin, messages
from django.urls import path, reverse
from django.shortcuts import render, redirect, get_object_or_404
from django.utils import timezone
from django.http import HttpResponseRedirect, HttpResponse
from django.utils.html import format_html
from .models import Lottery, Prize, LotteryParticipant, DrawResult
from .forms import AddParticipantsForm
from webapp.models import Invoice, Client, BindingRequest
from bot.notifications import NotificationService
from bot.utils import create_bot_instance

# Настройка логгера
logger = logging.getLogger(__name__)
logger.setLevel(logging.DEBUG)
if not logger.handlers:
    console_handler = logging.StreamHandler()
    console_handler.setLevel(logging.DEBUG)
    formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s')
    console_handler.setFormatter(formatter)
    logger.addHandler(console_handler)


def add_participants_view(request):
    lottery_id = request.GET.get("lottery_id")
    if not lottery_id:
        return HttpResponse("Не указан параметр lottery_id", status=400)
    lottery = get_object_or_404(Lottery, id=lottery_id)

    # Только счета, у которых used=False, и не добавленные в данную лотерею
    used_invoice_ids = LotteryParticipant.objects.filter(lottery=lottery).values_list("invoice_id", flat=True)
    qs = Invoice.objects.filter(used=False).exclude(id__in=used_invoice_ids)

    deposit_min = request.GET.get("deposit_min")
    deposit_max = request.GET.get("deposit_max")
    if deposit_min:
        qs = qs.filter(deposit_sum__gte=deposit_min)
    if deposit_max:
        qs = qs.filter(deposit_sum__lte=deposit_max)

    if request.method == "POST":
        form = AddParticipantsForm(request.POST)
        form.fields["invoices"].queryset = qs
        if form.is_valid():
            selected_invoices = form.cleaned_data["invoices"]
            for invoice in selected_invoices:
                # При добавлении участника отмечаем счет как использованный
                invoice.used = True
                invoice.save()
                LotteryParticipant.objects.create(lottery=lottery, invoice=invoice)
            messages.success(request, "Участники успешно добавлены.")
            return redirect("admin:draw_lotteryparticipant_changelist")
    else:
        form = AddParticipantsForm()
        form.fields["invoices"].queryset = qs

    context = {"form": form, "lottery": lottery}
    return render(request, "admin/add_participants.html", context)


def get_client_by_invoice(invoice):
    """
    Возвращает клиента, используя значение поля client_club_card_number у счета.
    Предполагается, что у модели Invoice есть поле client_club_card_number.
    """
    try:
        return Client.objects.get(club_card_number=invoice.client_club_card_number)
    except Client.DoesNotExist:
        return None


def start_draw(request, lottery_id):
    lottery = get_object_or_404(Lottery, id=lottery_id)
    logger.info("Запуск розыгрыша для лотереи: %s", lottery.name)

    # Если лотерея уже завершена, кнопку запускать не показываем
    if lottery.finished:
        messages.warning(request, "Розыгрыш уже завершён.")
        return redirect("..")

    notifier = NotificationService(bot=create_bot_instance())
    async_to_sync(notifier.notify_draw_start)(lottery)

    for prize in lottery.prizes.all():
        logger.info("Обработка приза: %s", prize.prize_place)

        # Если для приза уже назначен победитель вручную, сохраняем его в таблице результатов
        if prize.winner:
            logger.info("Приз '%s' имеет установленного вручную победителя. Сохраняем в таблице результатов.", prize.prize_place)
            try:
                draw_result = lottery.draw_results.get(prize=prize)
                draw_result.participant = prize.winner
                draw_result.drawn_at = timezone.now()
                draw_result.confirmed = False
                draw_result.save()
            except DrawResult.DoesNotExist:
                DrawResult.objects.create(
                    lottery=lottery,
                    prize=prize,
                    participant=prize.winner,
                    confirmed=False,
                    drawn_at=timezone.now()
                )
            continue

        try:
            draw_result = lottery.draw_results.get(prize=prize)
            if draw_result.confirmed:
                logger.info("Приз '%s' уже подтвержден.", prize.prize_place)
                continue
        except DrawResult.DoesNotExist:
            draw_result = None

        participants = list(lottery.participants.filter(used=False))
        logger.info("Найдено свободных участников для приза '%s': %d", prize.prize_place, len(participants))
        if not participants:
            logger.warning("Нет свободных участников для приза '%s'.", prize.prize_place)
            continue

        winner_participant = random.choice(participants)
        winner_participant.used = True
        winner_participant.save()
        logger.info("Выбран участник с счетом '%s' для приза '%s'.", winner_participant.invoice.api_id, prize.prize_place)

        if draw_result:
            draw_result.participant = winner_participant
            draw_result.drawn_at = timezone.now()
            draw_result.confirmed = False
            draw_result.save()
            logger.info("Обновлен результат розыгрыша для приза '%s'.", prize.prize_place)
        else:
            DrawResult.objects.create(
                lottery=lottery,
                prize=prize,
                participant=winner_participant,
                confirmed=False,
                drawn_at=timezone.now()
            )
            logger.info("Создан результат розыгрыша для приза '%s'.", prize.prize_place)

    draw_results = lottery.draw_results.all()
    async_to_sync(notifier.notify_draw_results)(lottery, draw_results)

    # Если все призы розыгрыша подтверждены, устанавливаем флаг завершения лотереи
    if not lottery.prizes.filter(winner__isnull=True).exists():
        lottery.finished = True
        lottery.save()

    return render(request, "admin/draw_result.html", {"lottery": lottery, "draw_results": draw_results})


def confirm_draw_result(request, result_id):
    from django.http import HttpResponseRedirect
    result = get_object_or_404(DrawResult, id=result_id)
    
    # Проверяем, что для результата задан участник и его счет
    if not result.participant or not result.participant.invoice:
        messages.error(request, "Невозможно подтвердить результат: отсутствует участник или его счет.")
        return HttpResponseRedirect(reverse("admin:start_draw", args=[result.lottery.id]))
    
    result.confirmed = True
    result.save()

    prize = result.prize
    prize.winner = result.participant
    prize.save()

    logger.info("Подтвержден результат розыгрыша для приза '%s'.", prize.prize_place)
    messages.success(request, f"Результат для приза '{prize.prize_place}' подтвержден.")

    # Получаем клиента по счету участника
    client = get_client_by_invoice(result.participant.invoice)
    # Если уведомление вызывает ошибки, можно временно его отключить,
    # чтобы проверить базовую функциональность подтверждения.
    if client:
        try:
            # Можно попробовать запуск уведомления в отдельном потоке или отключить его временно:
            async_to_sync(NotificationService(bot=create_bot_instance()).notify_prize_status_update)(client, result)
        except Exception as e:
            logger.error(f"Ошибка отправки уведомления о статусе приза пользователю {client.telegram_id}: {e}")

    return HttpResponseRedirect(reverse("admin:start_draw", args=[result.lottery.id]))


@admin.register(Lottery)
class LotteryAdmin(admin.ModelAdmin):
    list_display = ("name", "description", "created_at", "finished", "start_draw_button")
    search_fields = ("name", "description")

    def get_urls(self):
        urls = super().get_urls()
        custom_urls = [
            path('<int:lottery_id>/start-draw/', self.admin_site.admin_view(start_draw), name='start_draw'),
            path('confirm-draw-result/<int:result_id>/', self.admin_site.admin_view(confirm_draw_result), name='confirm_draw_result'),
        ]
        return custom_urls + urls

    def start_draw_button(self, obj):
        # Если лотерея завершена, кнопку скрываем
        if obj.finished:
            return ""
        url = reverse("admin:start_draw", args=[obj.pk])
        return format_html('<a class="btn btn-primary" href="{}">Запуск розыгрыша</a>', url)
    start_draw_button.short_description = "Розыгрыш"


@admin.register(Prize)
class PrizeAdmin(admin.ModelAdmin):
    list_display = ("lottery", "prize_place", "reward", "winner")
    list_filter = ("lottery",)
    search_fields = ("prize_place", "description")

    def get_form(self, request, obj=None, **kwargs):
        form = super().get_form(request, obj, **kwargs)
        # При создании нового приза поле winner скрываем, так как участников ещё нет
        if obj is None:
            form.base_fields.pop('winner', None)
        return form

    def formfield_for_foreignkey(self, db_field, request, **kwargs):
        if db_field.name == "winner" and request.resolver_match.kwargs.get('object_id'):
            obj_id = request.resolver_match.kwargs.get('object_id')
            try:
                prize_obj = self.model.objects.get(pk=obj_id)
                # Ограничиваем выбор участниками данной лотереи
                kwargs["queryset"] = prize_obj.lottery.participants.all()
            except self.model.DoesNotExist:
                kwargs["queryset"] = self.model.objects.none()
        return super().formfield_for_foreignkey(db_field, request, **kwargs)
    
    
@admin.register(LotteryParticipant)
class LotteryParticipantAdmin(admin.ModelAdmin):
    list_display = ("lottery", "invoice", "added_at", "used")
    list_filter = ("lottery", "used")
    search_fields = ("invoice__api_id", "lottery__name")
    change_list_template = "admin/draw/lotteryparticipant/change_list.html"

    def changelist_view(self, request, extra_context=None):
        extra_context = extra_context or {}
        from draw.models import Lottery
        active_lotteries = Lottery.objects.filter(prizes__winner__isnull=True).distinct()
        extra_context['active_lotteries'] = active_lotteries
        return super().changelist_view(request, extra_context=extra_context)

    def get_urls(self):
        from django.urls import path
        urls = super().get_urls()
        custom_urls = [
            path('add-participants/', self.admin_site.admin_view(add_participants_view), name="add_participants"),
        ]
        return custom_urls + urls


@admin.register(DrawResult)
class DrawResultAdmin(admin.ModelAdmin):
    list_display = ("lottery", "prize", "participant", "confirmed", "drawn_at")
    list_filter = ("lottery", "confirmed")
    search_fields = ("prize__prize_place", "participant__invoice__api_id")
