from django.shortcuts import render, get_object_or_404
from django.http import HttpResponse, HttpResponseRedirect, StreamingHttpResponse
from django.contrib.auth.decorators import login_required

from django.core.files.storage import FileSystemStorage
from django.core.paginator import Paginator
from django.db.models import Q, Case, When, Value, IntegerField

from .forms import SearchForm, URLImportForm

from .models import FA_User, FA_Tags, FA_Submission, FA_Submission_File

from .tasks import scrape_fa_submission, fa_import_data, test_task, calculate_square

import time, datetime, math

from django.contrib.auth.models import User, Group
from rest_framework import viewsets
from rest_framework import permissions
from .serializers import UserSerializer, GroupSerializer


class UserViewSet(viewsets.ModelViewSet):
    """
    API endpoint that allows users to be viewed or edited.
    """
    queryset = User.objects.all().order_by('-date_joined')
    serializer_class = UserSerializer
    permission_classes = [permissions.IsAuthenticated]


class GroupViewSet(viewsets.ModelViewSet):
    """
    API endpoint that allows groups to be viewed or edited.
    """
    queryset = Group.objects.all()
    serializer_class = GroupSerializer
    permission_classes = [permissions.IsAuthenticated]


# Create your views here.
def handle_task_result(task_result):
        # Handle the task result here
        print("Task completed! Result:", task_result)


@login_required(login_url="/login/")
def home(request):
    new_archives = FA_Submission.objects.order_by('-date_added')[:10]
    new_submissions = FA_Submission.objects.order_by('-date')[:10]
    context = {'new_archives': new_archives, "new_submissions": new_submissions}
    return render(request, 'fa/home.html', context)


# View Furaffinity submissions
@login_required(login_url="/login/")
def submission_detail(request, submission_id):
    submission = get_object_or_404(FA_Submission, submission_id=submission_id)
    file_url = submission.file.file.url if submission.file else None
    return render(request, 'fa/submission_detail.html', {'submission': submission, 'file_url': file_url})


@login_required(login_url="/login/")
def search_results(request):
    '''
    
    '''
    
    # Define a function to calculate relevance
    def calculate_relevance(queryset, search_query, fields):
        '''
        Calculate relevance scores for items in a queryset based on a search query.

        Parameters:
            queryset (QuerySet): The initial queryset that you want to annotate with relevance scores.
            search_query (str): The query string you want to search for within the specified fields.
            fields (list): A list of fields within the queryset where you want to search for the search_query.

        Returns:
            QuerySet: A queryset annotated with a "relevance" score for each item.
        '''
        # Create a list of "When" conditions for each field
        conditions = [When(**{f"{field}__icontains": search_query, 'then': Value(1)}) for field in fields]
        # Annotate the queryset with a "relevance" score
        # The "Case" expression evaluates the conditions and assigns a score of 1 if the search_query is found in any of the specified fields,
        # otherwise, it assigns a score of 0.
        return queryset.annotate(relevance=Case(*conditions, default=Value(0), output_field=IntegerField()))
    
    
    if request.method == 'GET':
        form = SearchForm(request.GET)
        if form.is_valid():
            search_query = form.cleaned_data['search_query']
            ## Perform the search on your data
            #title_description_results = FA_Submission.objects.filter(Q(title__icontains=search_query) | Q(description__icontains=search_query))
            #tag_results = FA_Submission.objects.filter(tags__tag__icontains=search_query)
            #
            ## Merge the title/content results and tag results, and remove duplicates
            #search_results = (title_description_results | tag_results).distinct()
            
            
            # Check if search_query starts with '#'
            if search_query.startswith('#'):
                # Strip '#' and split by spaces to get a list of tags
                tagshas = search_query.split()
                tags = []
                for tag in tagshas:
                    tags.append(tag.lstrip('#'))
                print(tags)
                # Create Q objects for each tag and chain them using OR
                q_objects = Q()
                for tag in tags:
                    q_objects |= Q(tags__tag__icontains=tag)

                print(q_objects)
                # Filter using the Q objects
                tag_results = calculate_relevance(FA_Submission.objects.filter(tags__tag__icontains=q_objects), q_objects, ['tags__tag'])
                print(tag_results)
                
                #search_results = calculate_relevance(FA_Submission.objects.filter(tags__tag__icontains=search_query), search_query, ['tags__tag'])
                # Order by relevance and remove duplicates
                search_results = tag_results.order_by('-relevance').distinct()
                #search_results = FA_Submission.objects.filter(tags__tag__icontains=search_query)
            else:
                # Perform the search on data
                # Calculate relevance for each queryset
                title_description_results = calculate_relevance(FA_Submission.objects.filter(Q(title__icontains=search_query) | Q(description__icontains=search_query)), search_query, ['title', 'description'])
                tag_results = calculate_relevance(FA_Submission.objects.filter(tags__tag__icontains=search_query), search_query, ['tags__tag'])

                # Merge the results, order by relevance and remove duplicates
                search_results = (title_description_results | tag_results).order_by('-relevance').distinct()
            
            
            # Set the number of submissions to display per page
            per_page = 10

            paginator = Paginator(search_results, per_page)
            page_number = request.GET.get('page')  # Get the current page number from the URL parameter
            page_obj = paginator.get_page(page_number)
            
            # Render the search results to a template
            context = {'search_results': page_obj}
            return render(request, 'fa/search_results.html', context)
    else:
        form = SearchForm()
    return render(request, 'fa/search_results.html', {'form': form})


@login_required(login_url="/login/")
def fa_users(request):
    list_users = FA_User.objects.order_by('artist')
    context = {'list_users': list_users}
    return render(request, 'fa/users.html', context)


@login_required(login_url="/login/")
def fa_user_page(request, fa_user):
    user = get_object_or_404(FA_User, artist_url=fa_user)
    user_submissions = FA_Submission.objects.filter(artist=user).order_by('-date')
    
    # Set the number of submissions to display per page
    per_page = 10

    paginator = Paginator(user_submissions, per_page)
    page_number = request.GET.get('page')  # Get the current page number from the URL parameter
    page_obj = paginator.get_page(page_number)
    
    context = {'user': user, 'page_obj': page_obj}
    return render(request, 'fa/user_page.html', context)
    #return HttpResponse("Your at FA_User index of %s." % fa_user)


@login_required(login_url="/login/")
def fa_tags(request):
    list_tags = FA_Tags.objects.order_by("tag")
    context = {'list_tags': list_tags}
    return render(request, 'fa/tags.html', context)


@login_required(login_url="/login/")
def tag_details(request, tag):
    tag_slug = get_object_or_404(FA_Tags, tag_slug=tag)
    submissions = FA_Submission.objects.filter(tags=tag_slug).order_by('-date')
    context = {'submissions': submissions, 'tag': tag_slug }
    return render(request, 'fa/tag_details.html', context)


@login_required(login_url="/login/")
def fa_config(request):
    return render(request, 'fa_config.html')


@login_required(login_url="/login/")
def fa_import(request):
    if request.method == 'POST':
        form = URLImportForm(request.POST)
        if form.is_valid():
            #print(form.cleaned_data['url'])
            result = scrape_fa_submission.delay(form.cleaned_data['url'])
            print(result)
            # Handle successful form submission
            # You can redirect to a success page or do other actions
            #return render(request, 'fa/import.html', {'form': form})
            return HttpResponseRedirect("/fa/")
            
    else:
        form = URLImportForm()
        
    return render(request, 'fa/import.html', {'form': form})


def stream_task_output(request, task_id):
    def event_stream():
        task = run_import_data.AsyncResult(task_id)
        while not task.ready():
            task_output = get_task_output(task_id)  # Implement a function to retrieve task output
            yield f"data: {task_output}\n\n"
            time.sleep(1)  # Adjust the delay between updates
        
    response = HttpResponse(event_stream(), content_type='text/event-stream')
    response['Cache-Control'] = 'no-cache'
    return response


def stream_datetime(request):
    def event_stream():
        while True:
            time.sleep(3)
            yield 'data: The server time is: %s\n\n' % datetime.datetime.now()
        
    response = StreamingHttpResponse(event_stream(), content_type='text/event-stream')
    response['Cache-Control'] = 'no-cache'
    return response


@login_required(login_url="/login/")
def stats(request):
    
    def convert_size(size_bytes):
        if size_bytes == 0:
            return "0B"
        size_name = ("B", "KiB", "MiB", "GiB", "TiB", "PiB", "EiB", "ZiB", "YiB")
        i = int(math.floor(math.log(size_bytes, 1024)))
        p = math.pow(1024, i)
        s = round(size_bytes / p, 2)
        return "%s %s" % (s, size_name[i])
    
    totalMediaSizeBytes = 0
    for files in FA_Submission_File.objects.all():
        totalMediaSizeBytes += files.file.size
    
    
    submissions    = FA_Submission.objects.count()
    users          = FA_User.objects.count()
    tags           = FA_Tags.objects.count()
    mediaFiles     = FA_Submission_File.objects.count()
    missingFiles   = len(FA_Submission.objects.filter(file__isnull=True))
    totalMediaSize = convert_size(totalMediaSizeBytes)
    
    context = {
        "submissions": submissions,
        "users": users,
        "tags": tags,
        "mediaFiles": mediaFiles,
        "missingFiles": missingFiles,
        "totalMediaSize": totalMediaSize,
    }
    return render(request, "fa/stats.html", context)


@login_required(login_url="/login/")
def simple_upload(request):
    if request.method == 'POST' and request.FILES['myfile']:
        myfile = request.FILES['myfile']
        fs = FileSystemStorage()
        filename = fs.save(myfile.name, myfile)
        uploaded_file_url = fs.url(filename)
        return render(request, 'fa/simple_upload.html', {
            'uploaded_file_url': uploaded_file_url
        })
    return render(request, 'fa/simple_upload.html')

#class FA_ImportView(generic.DetailView):
#    pass