import json

from django.http import Http404, JsonResponse
from django.urls import reverse, reverse_lazy
from django.utils import timezone
from django.utils.translation import gettext_lazy as _
from django.views import View
from django.views.generic import ListView, DetailView, CreateView, UpdateView, DeleteView
from rest_framework import viewsets, status
from rest_framework.decorators import action
from rest_framework.response import Response
from rest_framework.pagination import PageNumberPagination
from datetime import datetime
from .models import Post
from .templatetags.tasklist_markdown import update_task_in_markdown
from .forms import PostForm
from .serializers import PostSerializer
from .templatetags import markdown_extras, think_markdown

class PostListView(ListView):
    model = Post
    template_name = 'links/post_list.html'
    context_object_name = 'posts'
    paginate_by = 10

    def get_template_names(self):
        if self.request.headers.get('HX-Request'):
            return ['links/includes/post_list_items.html']
        return [self.template_name]

    def get_queryset(self):
        queryset = Post.objects.all().order_by('-created_at')

        # Date range filter
        date_from = self.request.GET.get('date_from')
        date_to = self.request.GET.get('date_to')

        if date_from:
            try:
                date_from = datetime.strptime(date_from, '%Y-%m-%d')
                queryset = queryset.filter(created_at__gte=date_from)
            except ValueError:
                pass

        if date_to:
            try:
                date_to = datetime.strptime(date_to, '%Y-%m-%d')
                queryset = queryset.filter(created_at__lte=date_to)
            except ValueError:
                pass

        return queryset

    def get_context_data(self, **kwargs):
        context = super().get_context_data(**kwargs)

        context['date_from'] = self.request.GET.get('date_from', '')
        context['date_to'] = self.request.GET.get('date_to', '')

        # Check if any filter is applied
        context['is_filtered'] = any([
            context['date_from'],
            context['date_to']
        ])

        return context

class PostDetailView(DetailView):
    model = Post
    template_name = 'links/post_detail.html'

class PostCreateView(CreateView):
    model = Post
    form_class = PostForm
    template_name = 'links/post_form.html'
    success_url = reverse_lazy('post-list')

class PostUpdateView(UpdateView):
    model = Post
    form_class = PostForm
    template_name = 'links/post_form.html'

    def get_success_url(self):
        return reverse_lazy('post-detail', kwargs={'pk': self.object.pk})

    def dispatch(self, request, *args, **kwargs):
        response = super().dispatch(request, *args, **kwargs)
        # Prevent caching to ensure fresh markdown content after task toggles
        response['Cache-Control'] = 'no-cache, no-store, must-revalidate'
        response['Pragma'] = 'no-cache'
        response['Expires'] = '0'
        return response

class PostDeleteView(DeleteView):
    model = Post
    template_name = 'links/post_confirm_delete.html'
    success_url = reverse_lazy('post-list')

class PublicPostView(DetailView):
    model = Post
    template_name = 'links/public_post.html'
    context_object_name = 'post'

    def get_context_data(self, **kwargs):
        context = super().get_context_data(**kwargs)
        context['markdown_extras'] = markdown_extras
        context['think_markdown'] = think_markdown
        return context

    def get_object(self, queryset=None):
        obj = super().get_object(queryset)
        if not obj.is_public:
            raise Http404("Post not found")
        return obj


class PostShareView(View):
    """Toggle public sharing for a post. POST body: {"enable": true|false}"""

    def post(self, request, pk):
        try:
            post = Post.objects.get(pk=pk)
        except Post.DoesNotExist:
            return JsonResponse({'error': 'Not found'}, status=404)

        try:
            body = json.loads(request.body or '{}')
            enable = bool(body.get('enable', True))
        except (json.JSONDecodeError, AttributeError):
            enable = True

        post.is_public = enable
        post.save(update_fields=['is_public'])

        public_url = (
            request.build_absolute_uri(reverse('public-post', args=[post.pk]))
            if post.is_public else None
        )
        return JsonResponse({'is_public': post.is_public, 'url': public_url})

class StandardResultsSetPagination(PageNumberPagination):
    page_size = 10
    page_size_query_param = 'page_size'
    max_page_size = 100

class PostViewSet(viewsets.ModelViewSet):
    queryset = Post.objects.all().order_by('-created_at')
    serializer_class = PostSerializer
    pagination_class = StandardResultsSetPagination

    def create(self, request, *args, **kwargs):
        serializer = self.get_serializer(data=request.data)
        serializer.is_valid(raise_exception=True)
        self.perform_create(serializer)
        headers = self.get_success_headers(serializer.data)
        return Response(serializer.data, status=status.HTTP_201_CREATED, headers=headers)

    def list(self, request, *args, **kwargs):
        queryset = self.filter_queryset(self.get_queryset())
        page = self.paginate_queryset(queryset)

        if page is not None:
            serializer = self.get_serializer(page, many=True)
            return self.get_paginated_response(serializer.data)

        serializer = self.get_serializer(queryset, many=True)
        return Response(serializer.data)

    @action(detail=True, methods=['post'])
    def append_content(self, request, pk=None):
        """
        Append markdown text to a post's existing content.

        POST /api/posts/{id}/append_content/
        Body: {"content": "## New section\n\nSome text"}
        """
        post = self.get_object()
        extra = request.data.get('content', '').strip()

        if not extra:
            return Response({'error': 'content is required'}, status=status.HTTP_400_BAD_REQUEST)

        post.content = post.content + '\n\n' + extra
        post.save(update_fields=['content', 'updated_at'])

        return Response({'status': 'ok'})

    @action(detail=True, methods=['post'])
    def toggle_task(self, request, pk=None):
        """
        Toggle the checked state of a task in a post.

        POST /api/posts/{id}/toggle_task/
        Body: {"task_hash": "abc123"}
        """
        post = self.get_object()
        task_hash = request.data.get('task_hash')

        if not task_hash:
            return Response(
                {'error': 'task_hash is required'},
                status=status.HTTP_400_BAD_REQUEST
            )

        # Get current task states or initialize empty dict
        task_states = post.task_states if post.task_states else {}

        # Toggle the state (default to False if not set, then toggle)
        current_state = task_states.get(task_hash, False)
        new_state = not current_state
        task_states[task_hash] = new_state

        # Save only task_states, leave markdown content unchanged
        post.task_states = task_states
        post.save(update_fields=['task_states', 'content', 'updated_at'])

        return Response({
            'task_hash': task_hash,
            'checked': new_state
        })
