import random
import logging
from asgiref.sync import async_to_sync
from datetime import datetime

from django import forms
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.utils.dateparse import parse_date
from django.utils.html import format_html
from django.http import HttpResponseRedirect, HttpResponse

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
from .views import view_draw_results
import os

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.filter(used=False).exclude(id__in=used_invoice_ids)

    deposit_min = request.GET.get("deposit_min")
    deposit_max = request.GET.get("deposit_max")
    created_after = request.GET.get("created_after")
    created_before = request.GET.get("created_before")

    if deposit_min:
        qs = qs.filter(deposit_sum__gte=deposit_min)
    if deposit_max:
        qs = qs.filter(deposit_sum__lte=deposit_max)
    if created_after:
        try:
            dt = parse_date(created_after)
            if dt:
                qs = qs.filter(created_at__gte=dt)
        except ValueError:
            pass
    if created_before:
        try:
            dt = parse_date(created_before)
            if dt:
                qs = qs.filter(created_at__lte=dt)
        except ValueError:
            pass

    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):
    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)

#     manually_assigned_invoice_ids = set()
#     for prize in lottery.prizes.all():
#         if prize.winner and prize.winner.invoice:
#             manually_assigned_invoice_ids.add(prize.winner.invoice_id)
#             prize.winner.used = True
#             prize.winner.save()

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

#         if prize.winner:
#             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:
#                 continue
#         except DrawResult.DoesNotExist:
#             draw_result = None

#         participants = list(
#             lottery.participants.filter(used=False).exclude(invoice_id__in=manually_assigned_invoice_ids)
#         )
#         if not participants:
#             continue

#         winner_participant = random.choice(participants)
#         winner_participant.used = True
#         winner_participant.save()

#         if draw_result:
#             draw_result.participant = winner_participant
#             draw_result.drawn_at = timezone.now()
#             draw_result.confirmed = False
#             draw_result.save()
#         else:
#             DrawResult.objects.create(
#                 lottery=lottery,
#                 prize=prize,
#                 participant=winner_participant,
#                 confirmed=False,
#                 drawn_at=timezone.now()
#             )

#     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 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())

    manually_assigned_invoice_ids = set()
    for prize in lottery.prizes.all():
        if prize.winner and prize.winner.invoice:
            manually_assigned_invoice_ids.add(prize.winner.invoice_id)
            prize.winner.used = True
            prize.winner.save()

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

        if prize.winner:
            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:
                continue
        except DrawResult.DoesNotExist:
            draw_result = None

        participants = list(
            lottery.participants.filter(used=False).exclude(invoice_id__in=manually_assigned_invoice_ids)
        )
        logger.info(f"Найдено участников: {len(participants)} для приза {prize.prize_place}")
        if not participants:
            continue

        winner_participant = random.choice(participants)
        winner_participant.used = True
        winner_participant.save()

        if draw_result:
            draw_result.participant = winner_participant
            draw_result.drawn_at = timezone.now()
            draw_result.confirmed = False
            draw_result.save()
        else:
            DrawResult.objects.create(
                lottery=lottery,
                prize=prize,
                participant=winner_participant,
                confirmed=False,
                drawn_at=timezone.now()
            )

    draw_results = lottery.draw_results.select_related('prize', 'participant__invoice')

    # 🧠 Считаем сумму призов и формируем список победителей
    total_reward = sum([r.prize.reward for r in draw_results if r.prize and r.prize.reward])
    winners_list = ""
    for r in draw_results:
        try:
            winners_list += f"• Счёт {r.participant.invoice.id} — {r.prize.reward}₩\\n"
        except Exception:
            continue

    async def notify_all():
        await notifier.notify_draw_start(lottery)
        await notifier.notify_draw_results(
            lottery,
            results=draw_results,
            context_vars={
                "total_reward": f"{total_reward:,}",
                "winners_list": winners_list.strip()
            }
        )

    async_to_sync(notify_all)()

    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):
    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()

    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}")

    messages.success(request, f"Результат для приза '{prize.prize_place}' подтвержден.")
    return HttpResponseRedirect(reverse("admin:view_draw_results", 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'),
            path('<int:lottery_id>/view-draw-results/', self.admin_site.admin_view(view_draw_results), name='view_draw_results'),
        ]
        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)
        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 {}
        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):
        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")
