from rest_framework import status
from rest_framework.decorators import api_view, permission_classes, parser_classes
from rest_framework.permissions import IsAuthenticated, AllowAny
from rest_framework.parsers import MultiPartParser, FormParser, JSONParser
from rest_framework.response import Response
from django.utils import timezone
from django.db.models import Q

from .models import BlogPost


# ---------- Public Endpoints ----------

@api_view(['GET'])
@permission_classes([AllowAny])
def blog_list(request):
    """List published blog posts with optional filtering."""
    posts = BlogPost.objects.filter(status='published').select_related('author')

    category = request.query_params.get('category')
    if category:
        posts = posts.filter(category=category)

    search = request.query_params.get('search')
    if search:
        posts = posts.filter(
            Q(title__icontains=search) |
            Q(excerpt__icontains=search) |
            Q(tags__icontains=search)
        )

    page = int(request.query_params.get('page', 1))
    limit = int(request.query_params.get('limit', 10))
    offset = (page - 1) * limit
    total = posts.count()
    posts = posts[offset:offset + limit]

    data = []
    for post in posts:
        data.append(_serialize_post(post, request))

    return Response({
        'results': data,
        'count': total,
        'page': page,
        'total_pages': (total + limit - 1) // limit if total > 0 else 1,
    })


@api_view(['GET'])
@permission_classes([AllowAny])
def blog_detail(request, slug):
    """Get a single published blog post by slug. Increments view count."""
    try:
        post = BlogPost.objects.select_related('author').get(slug=slug, status='published')
    except BlogPost.DoesNotExist:
        return Response({'error': 'Post not found'}, status=status.HTTP_404_NOT_FOUND)

    post.views_count += 1
    post.save(update_fields=['views_count'])

    return Response(_serialize_post(post, request, full=True))


# ---------- Admin Endpoints ----------

@api_view(['GET', 'POST'])
@permission_classes([IsAuthenticated])
@parser_classes([MultiPartParser, FormParser, JSONParser])
def admin_blog_list_create(request):
    """GET: list all posts (admin). POST: create a new post."""
    if request.user.user_type != 'admin':
        return Response({'error': 'Admin access required'}, status=status.HTTP_403_FORBIDDEN)

    if request.method == 'GET':
        posts = BlogPost.objects.select_related('author').all()

        status_filter = request.query_params.get('status')
        if status_filter:
            posts = posts.filter(status=status_filter)

        search = request.query_params.get('search')
        if search:
            posts = posts.filter(
                Q(title__icontains=search) | Q(excerpt__icontains=search)
            )

        page = int(request.query_params.get('page', 1))
        limit = int(request.query_params.get('limit', 10))
        offset = (page - 1) * limit
        total = posts.count()
        posts = posts[offset:offset + limit]

        data = [_serialize_post(p, request) for p in posts]
        return Response({
            'results': data,
            'count': total,
            'page': page,
            'total_pages': (total + limit - 1) // limit if total > 0 else 1,
        })

    # POST — create
    title = request.data.get('title', '').strip()
    if not title:
        return Response({'error': 'Title is required'}, status=status.HTTP_400_BAD_REQUEST)

    post = BlogPost(
        title=title,
        content=request.data.get('content', ''),
        excerpt=request.data.get('excerpt', ''),
        category=request.data.get('category', 'other'),
        tags=request.data.get('tags', ''),
        status=request.data.get('status', 'draft'),
        author=request.user,
    )

    if request.FILES.get('cover_image'):
        post.cover_image = request.FILES['cover_image']

    if post.status == 'published':
        post.published_at = timezone.now()

    post.save()
    return Response(_serialize_post(post, request, full=True), status=status.HTTP_201_CREATED)


@api_view(['GET', 'PATCH', 'DELETE'])
@permission_classes([IsAuthenticated])
@parser_classes([MultiPartParser, FormParser, JSONParser])
def admin_blog_detail(request, post_id):
    """GET/PATCH/DELETE a single blog post (admin)."""
    if request.user.user_type != 'admin':
        return Response({'error': 'Admin access required'}, status=status.HTTP_403_FORBIDDEN)

    try:
        post = BlogPost.objects.select_related('author').get(id=post_id)
    except BlogPost.DoesNotExist:
        return Response({'error': 'Post not found'}, status=status.HTTP_404_NOT_FOUND)

    if request.method == 'GET':
        return Response(_serialize_post(post, request, full=True))

    if request.method == 'DELETE':
        post.delete()
        return Response(status=status.HTTP_204_NO_CONTENT)

    # PATCH — update
    for field in ('title', 'content', 'excerpt', 'category', 'tags', 'status'):
        value = request.data.get(field)
        if value is not None:
            setattr(post, field, value)

    if request.FILES.get('cover_image'):
        post.cover_image = request.FILES['cover_image']

    # If newly published, set published_at
    if post.status == 'published' and not post.published_at:
        post.published_at = timezone.now()

    # Regenerate slug if title changed
    if 'title' in request.data:
        post.slug = ''  # reset so save() regenerates it

    post.save()
    return Response(_serialize_post(post, request, full=True))


# ---------- Helpers ----------

def _serialize_post(post, request, full=False):
    """Serialize a BlogPost to a dict."""
    data = {
        'id': post.id,
        'uuid': str(post.uuid),
        'title': post.title,
        'slug': post.slug,
        'excerpt': post.excerpt,
        'cover_image': request.build_absolute_uri(post.cover_image.url) if post.cover_image else None,
        'category': post.category,
        'tags': post.tags,
        'status': post.status,
        'views_count': post.views_count,
        'published_at': post.published_at.isoformat() if post.published_at else None,
        'created_at': post.created_at.isoformat(),
        'updated_at': post.updated_at.isoformat(),
        'author': {
            'id': post.author.id,
            'full_name': post.author.full_name,
        },
    }
    if full:
        data['content'] = post.content
    return data
