import os
from functools import wraps
from django.conf import settings
from django.shortcuts import render, redirect, get_object_or_404
from django.contrib.auth import login as auth_login, logout as auth_logout
from django.contrib.auth.models import User
from django.contrib import messages
from django.db.models import Sum
from django.core.paginator import Paginator
from django.urls import reverse
from urllib.parse import urlencode
from django.utils.http import url_has_allowed_host_and_scheme

from website.models import BlogPost, ContactMessage
from website.models.seo import PageSEOSetting
from website.forms import BlogPostForm
from dashboard.forms import DashboardLoginForm, PageSEOSettingForm

def staff_required(view_func):
    """
    Decorator that checks if the user is authenticated and is a staff member.
    Wraps the view function using functools.wraps to preserve docstrings/names.
    Redirects unauthenticated users to login with the '?next=' query parameter.
    """
    @wraps(view_func)
    def _wrapped_view(request, *args, **kwargs):
        if not request.user.is_authenticated:
            login_url = reverse('dashboard_login')
            query_string = urlencode({'next': request.path})
            return redirect(f"{login_url}?{query_string}")
        if not request.user.is_staff:
            messages.error(request, "Permission denied. Staff access required.")
            return redirect('home')
        return view_func(request, *args, **kwargs)
    return _wrapped_view



def dashboard_login(request):
    """
    Custom login view for the CMS dashboard.
    Demonstrates security handling of '?next=' query parameter redirects
    using standard scheme verification to prevent open redirect vulnerabilities.
    """
    if request.user.is_authenticated and request.user.is_staff:
        return redirect('dashboard_index')

    if request.method == 'POST':
        form = DashboardLoginForm(data=request.POST)
        if form.is_valid():
            user = form.get_user()
            if user and isinstance(user, User) and user.is_staff:
                auth_login(request, user)
                messages.success(request, f"Welcome back, {user.first_name or user.username}!")
                
                # Validate the redirect target to secure redirect path
                redirect_to = request.GET.get('next') or request.POST.get('next')
                if redirect_to and url_has_allowed_host_and_scheme(
                    url=redirect_to, 
                    allowed_hosts={request.get_host()}
                ):
                    return redirect(redirect_to)
                
                return redirect('dashboard_index')
            else:
                messages.error(request, "Access denied. Only staff members can access the dashboard.")
        else:
            messages.error(request, "Invalid username or password.")
    else:
        form = DashboardLoginForm()

    return render(request, 'dashboard/login.html', {'form': form})



def dashboard_logout(request):
    """
    Logs out the user and redirects to login page.
    """
    auth_logout(request)
    messages.info(request, "You have been logged out.")
    return redirect('dashboard_login')


@staff_required
def dashboard_index(request):
    """
    Dashboard landing page displaying system statistics and recent entries.
    """
    blog_qs = BlogPost.objects.all()
    leads_qs = ContactMessage.objects.all()

    # Aggregate stats
    total_posts = blog_qs.count()
    published_posts = blog_qs.filter(status='PUBLISHED').count()
    draft_posts = blog_qs.filter(status='DRAFT').count()
    
    total_views = blog_qs.aggregate(Sum('views_count'))['views_count__sum'] or 0
    total_leads = leads_qs.count()

    # Recent lists
    recent_posts = blog_qs.order_by('-created_at')[:5]
    recent_leads = leads_qs.order_by('-created_at')[:5]

    context = {
        'total_posts': total_posts,
        'published_posts': published_posts,
        'draft_posts': draft_posts,
        'total_views': total_views,
        'total_leads': total_leads,
        'recent_posts': recent_posts,
        'recent_leads': recent_leads,
        'active_tab': 'dashboard'
    }
    return render(request, 'dashboard/index.html', context)


@staff_required
def dashboard_blog_list(request):
    """
    Tabular list of blog posts in the CMS.
    """
    query = request.GET.get('q', '').strip()
    status_filter = request.GET.get('status', '').strip()
    
    posts = BlogPost.objects.all()
    
    if query:
        posts = posts.filter(title__icontains=query)
    if status_filter in ['PUBLISHED', 'DRAFT']:
        posts = posts.filter(status=status_filter)

    paginator = Paginator(posts, 10)
    page_number = request.GET.get('page')
    page_obj = paginator.get_page(page_number)

    context = {
        'page_obj': page_obj,
        'query': query,
        'status_filter': status_filter,
        'active_tab': 'blogs'
    }
    return render(request, 'dashboard/blog_list.html', context)


@staff_required
def dashboard_blog_create(request):
    """
    Dashboard view to create a new blog post.
    """
    if request.method == 'POST':
        form = BlogPostForm(request.POST, request.FILES)
        if form.is_valid():
            post = form.save(commit=False)
            post.author = request.user
            post.save()
            messages.success(request, f"Blog post '{post.title}' created successfully!")
            return redirect('dashboard_blog_list')
        else:
            messages.error(request, "Failed to create post. Please check the errors below.")
    else:
        form = BlogPostForm()

    context = {
        'form': form,
        'action': 'Create',
        'active_tab': 'blogs'
    }
    return render(request, 'dashboard/blog_form.html', context)


@staff_required
def dashboard_blog_update(request, slug):
    """
    Dashboard view to edit an existing blog post.
    """
    post = get_object_or_404(BlogPost, slug=slug)
    if request.method == 'POST':
        form = BlogPostForm(request.POST, request.FILES, instance=post)
        if form.is_valid():
            form.save()
            messages.success(request, f"Blog post '{post.title}' updated successfully!")
            return redirect('dashboard_blog_list')
        else:
            messages.error(request, "Failed to update post. Please check the errors below.")
    else:
        form = BlogPostForm(instance=post)

    context = {
        'form': form,
        'post': post,
        'action': 'Update',
        'active_tab': 'blogs'
    }
    return render(request, 'dashboard/blog_form.html', context)


@staff_required
def dashboard_blog_delete(request, slug):
    """
    Delete a blog post.
    """
    post = get_object_or_404(BlogPost, slug=slug)
    post_title = post.title
    post.delete()
    messages.success(request, f"Blog post '{post_title}' has been deleted.")
    return redirect('dashboard_blog_list')


@staff_required
def dashboard_lead_list(request):
    """
    Tabular list of contact inquiries in the CMS.
    """
    query = request.GET.get('q', '').strip()
    leads = ContactMessage.objects.all()

    if query:
        leads = leads.filter(name__icontains=query) | leads.filter(subject__icontains=query)

    paginator = Paginator(leads, 10)
    page_number = request.GET.get('page')
    page_obj = paginator.get_page(page_number)

    context = {
        'page_obj': page_obj,
        'query': query,
        'active_tab': 'leads'
    }
    return render(request, 'dashboard/lead_list.html', context)


@staff_required
def dashboard_lead_detail(request, pk):
    """
    Detail page for a single contact inquiry.
    """
    lead = get_object_or_404(ContactMessage, pk=pk)
    context = {
        'lead': lead,
        'active_tab': 'leads'
    }
    return render(request, 'dashboard/lead_detail.html', context)


@staff_required
def dashboard_lead_delete(request, pk):
    """
    Delete a contact inquiry/lead.
    """
    lead = get_object_or_404(ContactMessage, pk=pk)
    lead.delete()
    messages.success(request, "Lead deleted successfully.")
    return redirect('dashboard_lead_list')


def get_all_configurable_pages():
    """
    Returns a combined list of static pages and dynamic service pages
    by scanning the `website/templates/website/services/` directory.
    """
    pages = [
        ('home', 'Home Page'),
        ('about', 'About Page'),
        ('services', 'Services Hub Page'),
        ('blog', 'Blog List Page'),
        ('contact', 'Contact Page'),
        ('team', 'Team Page'),
    ]
    
    # Path to website/templates/website/services/
    services_dir = os.path.join(settings.BASE_DIR, 'website', 'templates', 'website', 'services')
    if os.path.exists(services_dir):
        for file in os.listdir(services_dir):
            if file.endswith('.html'):
                slug = file[:-5] # remove '.html'
                label = slug.replace('-', ' ').title()
                pages.append((f"service_{slug}", f"Service: {label}"))
                
    return pages


@staff_required
def dashboard_seo_list(request):
    """
    Renders the SEO settings management dashboard homepage.
    """
    valid_pages = get_all_configurable_pages()
    settings_dict = {s.page_name: s for s in PageSEOSetting.objects.all()}
    
    pages_data = []
    for page_code, page_label in valid_pages:
        setting = settings_dict.get(page_code)
        pages_data.append({
            'code': page_code,
            'label': page_label,
            'is_configured': setting is not None,
            'setting': setting
        })
        
    context = {
        'pages_data': pages_data,
        'active_tab': 'seo',
    }
    return render(request, 'dashboard/seo_list.html', context)


@staff_required
def dashboard_seo_edit(request, page_name):
    """
    Renders and processes the form to update SEO Settings for a single page.
    Uses get_or_create to automatically initialize the page's record if it doesn't exist yet.
    """
    valid_pages = dict(get_all_configurable_pages())
    if page_name not in valid_pages:
        messages.error(request, "Invalid page selected.")
        return redirect('dashboard_seo_list')
        
    # Automatically get or initialize the SEO record for the page
    seo_setting, created = PageSEOSetting.objects.get_or_create(page_name=page_name)
    
    if request.method == 'POST':
        form = PageSEOSettingForm(request.POST, request.FILES, instance=seo_setting)
        if form.is_valid():
            form.save()
            messages.success(request, f"SEO Settings for '{valid_pages[page_name]}' updated successfully!")
            return redirect('dashboard_seo_list')
    else:
        form = PageSEOSettingForm(instance=seo_setting)
        
    context = {
        'form': form,
        'page_name': page_name,
        'page_title': valid_pages[page_name],
        'seo_setting': seo_setting,
        'active_tab': 'seo',
    }
    return render(request, 'dashboard/seo_form.html', context)
