import os
import platform

from django import get_version as django_version
from django.contrib import messages
from django.db.models import Count, Prefetch, Q
from django.http import Http404
from django.shortcuts import get_object_or_404, redirect, render
from django.urls import reverse
from django.utils import timezone

from .forms import ConversationStartForm, MessageForm, ProfileForm, REACTION_CHOICES, ReactionForm
from .models import Conversation, Message, ResakaProfile


DEFAULT_META_DESCRIPTION = (
    "RJL Resaka est une messagerie privée moderne pour lancer des conversations, "
    "envoyer des messages et suivre les notifications de lecture."
)


def _profile_from_request(request):
    profiles = ResakaProfile.objects.order_by("display_name")
    profile = None
    requested_id = request.GET.get("profile") or request.session.get("active_profile_id")

    if requested_id:
        try:
            profile = profiles.get(pk=requested_id)
        except (ResakaProfile.DoesNotExist, ValueError, TypeError):
            profile = None

    if not profile and profiles.exists():
        profile = profiles.first()

    if profile:
        request.session["active_profile_id"] = profile.pk

    return profile, profiles


def _profile_query_suffix(profile):
    return f"?profile={profile.pk}" if profile else ""


def _conversation_queryset(active_profile):
    base = Conversation.objects.select_related("starter", "recipient").prefetch_related(
        Prefetch(
            "messages",
            queryset=Message.objects.select_related("author").order_by("created_at"),
        )
    )
    if active_profile:
        base = base.filter(Q(starter=active_profile) | Q(recipient=active_profile)).annotate(
            unread_count=Count(
                "messages",
                filter=Q(messages__is_read=False) & ~Q(messages__author=active_profile),
            )
        )
    else:
        base = base.none()
    return base.order_by("-updated_at")


def home(request):
    host_name = request.get_host().lower()
    agent_brand = "AppWizzy" if host_name == "appwizzy.com" else "Flatlogic"
    now = timezone.now()
    active_profile, profiles = _profile_from_request(request)
    conversations = list(_conversation_queryset(active_profile))

    for conversation in conversations:
        message_list = list(conversation.messages.all())
        conversation.last_message = message_list[-1] if message_list else None
        conversation.counterpart = conversation.counterpart_for(active_profile)

    stats = {
        "profiles": profiles.count(),
        "conversations": len(conversations),
        "messages": Message.objects.count(),
    }

    context = {
        "project_name": "RJL Resaka",
        "agent_brand": agent_brand,
        "django_version": django_version(),
        "python_version": platform.python_version(),
        "current_time": now,
        "host_name": host_name,
        "project_description": os.getenv("PROJECT_DESCRIPTION", DEFAULT_META_DESCRIPTION),
        "project_image_url": os.getenv("PROJECT_IMAGE_URL", ""),
        "page_title": "RJL Resaka | Messagerie privée moderne",
        "page_description": DEFAULT_META_DESCRIPTION,
        "active_profile": active_profile,
        "profiles": profiles,
        "profile_form": ProfileForm(),
        "conversation_form": ConversationStartForm(active_profile=active_profile),
        "conversations": conversations,
        "stats": stats,
        "profile_query": _profile_query_suffix(active_profile),
    }
    return render(request, "core/index.html", context)


def create_profile(request):
    if request.method != "POST":
        return redirect("home")

    form = ProfileForm(request.POST)
    if form.is_valid():
        profile = form.save()
        request.session["active_profile_id"] = profile.pk
        messages.success(request, f"Profil {profile.display_name} créé. Vous pouvez maintenant lancer une discussion.")
        return redirect(f"{reverse('home')}?profile={profile.pk}")

    active_profile, profiles = _profile_from_request(request)
    conversations = list(_conversation_queryset(active_profile))
    for conversation in conversations:
        message_list = list(conversation.messages.all())
        conversation.last_message = message_list[-1] if message_list else None
        conversation.counterpart = conversation.counterpart_for(active_profile)

    context = {
        "project_name": "RJL Resaka",
        "page_title": "Créer un profil | RJL Resaka",
        "page_description": DEFAULT_META_DESCRIPTION,
        "active_profile": active_profile,
        "profiles": profiles,
        "profile_form": form,
        "conversation_form": ConversationStartForm(active_profile=active_profile),
        "conversations": conversations,
        "stats": {
            "profiles": profiles.count(),
            "conversations": len(conversations),
            "messages": Message.objects.count(),
        },
        "profile_query": _profile_query_suffix(active_profile),
        "current_time": timezone.now(),
        "django_version": django_version(),
        "python_version": platform.python_version(),
    }
    return render(request, "core/index.html", context, status=400)


def start_conversation(request):
    if request.method != "POST":
        return redirect("home")

    active_profile, _profiles = _profile_from_request(request)
    if not active_profile:
        messages.error(request, "Créez ou sélectionnez d'abord un profil pour discuter.")
        return redirect("home")

    form = ConversationStartForm(request.POST, active_profile=active_profile)
    if not form.is_valid():
        messages.error(request, "Impossible de lancer la discussion. Vérifiez les champs du formulaire.")
        return redirect(f"{reverse('home')}?profile={active_profile.pk}")

    recipient = form.cleaned_data["recipient"]
    body = form.cleaned_data["body"]
    conversation = (
        Conversation.objects.filter(
            (Q(starter=active_profile) & Q(recipient=recipient))
            | (Q(starter=recipient) & Q(recipient=active_profile))
        )
        .select_related("starter", "recipient")
        .first()
    )
    created = False
    if not conversation:
        conversation = Conversation.objects.create(
            starter=active_profile,
            recipient=recipient,
            subject=f"Discussion privée · {active_profile.display_name} & {recipient.display_name}",
        )
        created = True

    Message.objects.create(
        conversation=conversation,
        author=active_profile,
        body=body,
        is_read=False,
    )
    conversation.save(update_fields=["updated_at"])

    if created:
        messages.success(request, f"Nouvelle conversation lancée avec {recipient.display_name}.")
    else:
        messages.success(request, f"Message envoyé à {recipient.display_name}.")
    return redirect(f"{conversation.get_absolute_url()}?profile={active_profile.pk}")


def conversation_detail(request, pk):
    active_profile, profiles = _profile_from_request(request)
    conversation = get_object_or_404(
        Conversation.objects.select_related("starter", "recipient").prefetch_related(
            Prefetch("messages", queryset=Message.objects.select_related("author").order_by("created_at"))
        ),
        pk=pk,
    )

    if not active_profile or active_profile.pk not in {conversation.starter_id, conversation.recipient_id}:
        if active_profile:
            messages.error(request, "Cette conversation n'appartient pas au profil sélectionné.")
            return redirect(f"{reverse('home')}?profile={active_profile.pk}")
        messages.error(request, "Sélectionnez un profil pour ouvrir une conversation.")
        return redirect("home")

    if request.method == "POST":
        form = MessageForm(request.POST)
        if form.is_valid():
            message = form.save(commit=False)
            message.conversation = conversation
            message.author = active_profile
            message.is_read = False
            message.save()
            conversation.save(update_fields=["updated_at"])
            messages.success(request, "Message envoyé.")
            return redirect(f"{conversation.get_absolute_url()}?profile={active_profile.pk}")
    else:
        form = MessageForm()

    Message.objects.filter(conversation=conversation).exclude(author=active_profile).filter(is_read=False).update(is_read=True)

    message_list = list(conversation.messages.all())
    counterpart = conversation.counterpart_for(active_profile)
    reaction_forms = {message.pk: ReactionForm() for message in message_list}

    context = {
        "project_name": "RJL Resaka",
        "page_title": f"Chat avec {counterpart.display_name} | RJL Resaka",
        "page_description": f"Conversation privée entre {active_profile.display_name} et {counterpart.display_name} sur RJL Resaka.",
        "active_profile": active_profile,
        "profiles": profiles,
        "conversation": conversation,
        "counterpart": counterpart,
        "message_form": form,
        "messages_list": message_list,
        "reaction_forms": reaction_forms,
        "reaction_choices": REACTION_CHOICES,
        "profile_query": _profile_query_suffix(active_profile),
    }
    return render(request, "core/chat_detail.html", context)


def react_message(request, pk):
    if request.method != "POST":
        raise Http404

    active_profile, _profiles = _profile_from_request(request)
    message = get_object_or_404(Message.objects.select_related("conversation", "author"), pk=pk)
    conversation = message.conversation
    if not active_profile or active_profile.pk not in {conversation.starter_id, conversation.recipient_id}:
        messages.error(request, "Sélectionnez un profil valide pour réagir au message.")
        return redirect("home")

    form = ReactionForm(request.POST)
    if form.is_valid():
        message.reaction = form.cleaned_data["reaction"]
        message.save(update_fields=["reaction"])
        messages.success(request, "Réaction envoyée.")
    else:
        messages.error(request, "Réaction invalide.")
    return redirect(f"{conversation.get_absolute_url()}?profile={active_profile.pk}")
