import logging

# from django.contrib.auth.decorators import login_required
from django.contrib import messages
from django.http import JsonResponse
from django.shortcuts import redirect, render
from django.urls import reverse

from .models import Flashcard, Material
from .services import COLORS, LLMError, extract_pdf_text, generate_flashcards
from .utils import *

logger = logging.getLogger(__name__)

UPLOAD_TEMPLATE = "Create_file.html"


def _cards_page(material):
    """Send the teacher straight to the page that shows this material's cards."""
    return redirect(f"{reverse('flashcards:flashcards_page')}?material={material.pk}")


# @login_required
def create_material(request):
    if request.method != "POST":
        return render(request, UPLOAD_TEMPLATE)

    title = request.POST.get("title", "").strip() or "Untitled material"
    text = request.POST.get("text", "")
    pdf = request.FILES.get("pdf")

    if not pdf and not text.strip():
        messages.error(request, "Add a PDF or write some content first.")
        return render(request, UPLOAD_TEMPLATE)

    # 1. Save the material first so it is kept even if the AI step fails.
    material = Material.objects.create(
        teacher=request.user if request.user.is_authenticated else None,
        title=title,
        text=text,
        pdf=pdf,
    )

    # 2. Collect the text to send to the AI (typed text + PDF text).
    full_text = material.text
    if material.pdf:
        try:
            full_text += "\n" + extract_pdf_text(material.pdf.path)
        except Exception:
            logger.exception("Could not read the PDF for material %s", material.pk)
            messages.warning(request, "The PDF could not be read. Try another file.")

    if not full_text.strip():
        messages.warning(
            request,
            "Material saved, but no readable text was found. Scanned PDFs are not supported.",
        )
        return _cards_page(material)

    # 3. Ask the AI for flashcards. An offline model server must not crash the page.
    try:
        generated = generate_flashcards(full_text)
    except LLMError as exc:
        logger.warning("AI generation failed for material %s: %s", material.pk, exc)
        messages.warning(
            request,
            "Material saved, but flashcards could not be generated because the AI server did not respond.",
        )
        return _cards_page(material)

    if not generated:
        messages.warning(request, "Material saved, but the AI found no key points to turn into flashcards.")
        return _cards_page(material)

    # 4. Save all cards in one query, each with a different color.
    Flashcard.objects.bulk_create(
        [
            Flashcard(
                material=material,
                title=card["title"][:120],
                content=card["content"],
                color=COLORS[i % len(COLORS)],
                order=i,
            )
            for i, card in enumerate(generated)
        ]
    )
    messages.success(request, f"{len(generated)} flashcards created.")
    return _cards_page(material)


def cards_api(request):
    material_id = request.GET.get("material", "").strip()

    if material_id.isdigit():
        # A specific material was requested (for example on a course page).
        qs = Flashcard.objects.filter(material_id=int(material_id))
    else:
        # Default: the newest material that actually has cards.
        latest = (
            Material.objects.filter(cards__isnull=False)
            .distinct()
            .order_by("-created_at")
            .first()
        )
        qs = Flashcard.objects.filter(material=latest) if latest else Flashcard.objects.none()

    return JsonResponse({"cards": list(qs.values("id", "title", "content", "color", "order"))})


def flashcards_page(request):
    """Full page that shows the flashcards of one material as colored cards."""
    materials = Material.objects.filter(cards__isnull=False).distinct().order_by("-created_at")

    material_id = request.GET.get("material", "").strip()
    if material_id.isdigit():
        # An explicit material is shown even if it has no cards yet (for example after a failed AI call).
        material = Material.objects.filter(pk=int(material_id)).first()
    else:
        material = materials.first()

    cards = []
    if material:
        cards = [
            {
                "title": card.title,
                "content": card.content,
                "color": card.color,
                "fg": text_color(card.color),
            }
            for card in material.cards.all()
        ]

    return render(
        request,
        "flashcards_page.html",
        {"material": material, "materials": materials, "cards": cards},
    )