from django.contrib import messages
from django.db.models import Count, Q
from django.core.paginator import Paginator
from django.shortcuts import get_object_or_404, redirect, render
from django.utils import timezone

from .forms import JobPostingForm, JobSourceForm
from .models import JobPosting, JobSource


PAGE_META = {
    "project_name": "Dijon Job Aggregator",
    "project_description": "Pilot dashboard for collecting, reviewing, and searching job offers around Dijon.",
}


def _meta(title, description=None):
    return {
        **PAGE_META,
        "page_title": title,
        "meta_description": description or PAGE_META["project_description"],
    }


def home(request):
    """Landing dashboard with search, source stats, and latest offers."""
    latest_jobs = JobPosting.objects.select_related("source").filter(is_active=True)[:6]
    sources_by_family = JobSource.objects.values("family").annotate(total=Count("id")).order_by("family")
    context = {
        **_meta("Dijon Job Aggregator — Pilot Dashboard"),
        "total_jobs": JobPosting.objects.count(),
        "active_jobs": JobPosting.objects.filter(is_active=True).count(),
        "source_count": JobSource.objects.count(),
        "sources_by_family": sources_by_family,
        "latest_jobs": latest_jobs,
        "today": timezone.localdate(),
    }
    return render(request, "core/index.html", context)


def source_create(request):
    if request.method == "POST":
        form = JobSourceForm(request.POST)
        if form.is_valid():
            source = form.save()
            messages.success(request, "Source registered. You can now attach job offers to it.")
            return redirect("source_success", pk=source.pk)
    else:
        form = JobSourceForm(initial={"status": JobSource.Status.PLANNED})
    return render(
        request,
        "core/source_form.html",
        {**_meta("Register a Source", "Add a job portal, agency, or careers page to the Dijon aggregation pipeline."), "form": form},
    )


def source_success(request, pk):
    source = get_object_or_404(JobSource.objects.annotate(job_count=Count("jobs")), pk=pk)
    return render(
        request,
        "core/source_success.html",
        {**_meta("Source Registered", "Connector source confirmation for the Dijon Job Aggregator."), "source": source},
    )


def job_create(request):
    if not JobSource.objects.exists():
        messages.info(request, "Create your first source before adding a job offer.")
        return redirect("source_create")
    if request.method == "POST":
        form = JobPostingForm(request.POST)
        if form.is_valid():
            job = form.save()
            messages.success(request, "Job offer added to the review queue.")
            return redirect("job_success", pk=job.pk)
    else:
        form = JobPostingForm()
    return render(
        request,
        "core/job_form.html",
        {**_meta("Add a Job Offer", "Create a normalized job offer linked to a registered source."), "form": form},
    )


def job_success(request, pk):
    job = get_object_or_404(JobPosting.objects.select_related("source"), pk=pk)
    return render(
        request,
        "core/job_success.html",
        {**_meta("Offer Added", "Confirmation page for a newly captured Dijon job offer."), "job": job},
    )


def job_list(request):
    query = request.GET.get("q", "").strip()
    contract = request.GET.get("contract", "").strip()
    family = request.GET.get("family", "").strip()
    source_status = request.GET.get("source_status", "").strip()
    sort = request.GET.get("sort", "newest").strip()

    job_sort_map = {
        "newest": "-created_at",
        "oldest": "created_at",
        "company_az": "company",
        "company_za": "-company",
    }
    order_by = job_sort_map.get(sort, "-created_at")

    jobs_qs = JobPosting.objects.select_related("source").filter(is_active=True)
    if query:
        jobs_qs = jobs_qs.filter(
            Q(title__icontains=query)
            | Q(company__icontains=query)
            | Q(location__icontains=query)
            | Q(description__icontains=query)
        )
    if contract:
        jobs_qs = jobs_qs.filter(contract_type=contract)
    if family:
        jobs_qs = jobs_qs.filter(source__family=family)
    if source_status:
        jobs_qs = jobs_qs.filter(source__status=source_status)
    jobs_qs = jobs_qs.order_by(order_by)

    paginator = Paginator(jobs_qs, 9)
    page_number = request.GET.get("page")
    jobs = paginator.get_page(page_number)

    filters = request.GET.copy()
    filters.pop("page", None)
    current_filters_qs = filters.urlencode()

    context = {
        **_meta("Search Job Offers", "Search normalized job offers collected for Dijon and nearby opportunities."),
        "jobs": jobs,
        "query": query,
        "contract": contract,
        "family": family,
        "source_status": source_status,
        "sort": sort,
        "contract_choices": JobPosting.ContractType.choices,
        "family_choices": JobSource.Family.choices,
        "source_status_choices": JobSource.Status.choices,
        "result_count": jobs_qs.count(),
        "current_filters_qs": current_filters_qs,
    }
    return render(request, "core/job_list.html", context)


def job_detail(request, pk):
    job = get_object_or_404(JobPosting.objects.select_related("source"), pk=pk)
    related_jobs = (
        JobPosting.objects.select_related("source")
        .filter(is_active=True, company__iexact=job.company)
        .exclude(pk=job.pk)[:3]
    )
    return render(
        request,
        "core/job_detail.html",
        {**_meta(job.title, f"{job.title} at {job.company} — normalized offer from {job.source.name}."), "job": job, "related_jobs": related_jobs},
    )

def ops_dashboard(request):
    query = request.GET.get("q", "").strip()
    family = request.GET.get("family", "").strip()
    status = request.GET.get("status", "").strip()
    sort = request.GET.get("sort", "family_name").strip()

    source_sort_map = {
        "family_name": ("family", "name"),
        "name_az": ("name",),
        "name_za": ("-name",),
        "status": ("status", "name"),
        "offers_high": ("-job_total", "name"),
        "offers_low": ("job_total", "name"),
    }
    source_order_by = source_sort_map.get(sort, ("family", "name"))

    sources_qs = JobSource.objects.annotate(job_total=Count("jobs")).order_by(*source_order_by)
    if query:
        sources_qs = sources_qs.filter(Q(name__icontains=query) | Q(owner__icontains=query) | Q(url__icontains=query))
    if family:
        sources_qs = sources_qs.filter(family=family)
    if status:
        sources_qs = sources_qs.filter(status=status)

    paginator = Paginator(sources_qs, 8)
    page_number = request.GET.get("page")
    sources = paginator.get_page(page_number)

    filters = request.GET.copy()
    filters.pop("page", None)
    current_filters_qs = filters.urlencode()

    recent_jobs = (
        JobPosting.objects.select_related("source")
        .order_by("-created_at")[:8]
    )
    family_breakdown = (
        JobSource.objects.values("family")
        .annotate(total=Count("id"), jobs=Count("jobs"))
        .order_by("family")
    )
    status_breakdown = (
        JobSource.objects.values("status")
        .annotate(total=Count("id"))
        .order_by("status")
    )
    needs_attention = sources_qs.filter(status=JobSource.Status.ERROR).count()
    stale_sources = sources_qs.filter(last_checked_at__isnull=True).count()
    return render(
        request,
        "core/ops_dashboard.html",
        {
            **_meta(
                "Ops dashboard · Dijon Job Aggregator",
                "Monitor source readiness, intake recency, and connector-family coverage for the Dijon job aggregator pilot.",
            ),
            "sources": sources,
            "recent_jobs": recent_jobs,
            "family_breakdown": family_breakdown,
            "status_breakdown": status_breakdown,
            "needs_attention": needs_attention,
            "stale_sources": stale_sources,
            "active_jobs": JobPosting.objects.filter(is_active=True).count(),
            "total_sources": sources_qs.count(),
            "query": query,
            "family": family,
            "status": status,
            "sort": sort,
            "family_choices": JobSource.Family.choices,
            "status_choices": JobSource.Status.choices,
            "current_filters_qs": current_filters_qs,
        },
    )
