import os
import re
import logging
from decouple import config
from datetime import datetime
from moviepy.editor import VideoFileClip
from django.contrib.auth.models import User
from django.views.decorators.cache import cache_page
from django.core import serializers
from django.http import HttpResponse, JsonResponse , Http404
from django.contrib.auth.decorators import login_required
from django.shortcuts import render, redirect
from django.views import View

import boto
import boto.s3.connection
from boto.s3.key import Key

from rest_framework import status
from rest_framework.views import APIView
from rest_framework.response import Response

from .tasks import check_transcripts
from .models import File, Transcripts
from .utils import generate_name, handle_uploaded_file
from .serializers import FileSerializer,TranscriptsSerializer

logger = logging.getLogger(__file__)


class ListTranscripts(View):
    def get(self,request):
        if not request.user.is_authenticated:
            return redirect("accounts:login")
        transcripts=None
        if request.user.is_superuser:
            transcripts = Transcripts.objects.all()
        else :
            transcripts = Transcripts.objects.filter(file_org__user=request.user)
        logger.info(transcripts)
        context = {
            "transcripts":transcripts,
            "page":"allTranscripts"
        }

        return render(request, 'dashboard.html', context)


@login_required(login_url='/auth/login')
def upload(request):
    if not request.user.is_authenticated:
        return redirect("accounts:login")
    if request.method == 'POST' and ('filename' in request.FILES ):
        filename= request.FILES['filename'].name
        content = request.FILES['filename']
        path="media/"
        if not os.path.exists(path):
            os.makedirs(path)
        # generate unique name
        generated_name = generate_name(filename)

        # handle upload file to local server
        handle_uploaded_file(content, path, generated_name)

        # save file info in database
        video_path = path+generated_name
        clip = VideoFileClip(video_path)
        filename, extension = os.path.splitext(filename)
        # Create File Object & Save IT
        new_file = File(
            file_title    = filename,
            video_path    = video_path,
            duration      = clip.duration,
            extension     = extension,
            size          = os.path.getsize(video_path),
            user          = request.user
        )
        new_file.save()

        # Create an S3 client object using the Boto3 library
        conn = boto.s3.connect_to_region(
            region_name = config("AWS_REGION", default="us-west-2", cast=str),
            aws_access_key_id = config("AWS_ACCESS_KEY_ID", default="AKIAT6THLFM7NTAL4XWX", cast=str),
            aws_secret_access_key = config("AWS_SECRET_ACCESS_KEY", default="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", cast=str),
            calling_format = boto.s3.connection.OrdinaryCallingFormat(),
        )
        # Try to get the bucket by name
        bucket = conn.get_bucket('input-transcribe-bucket')
        # Create a new Key object that can be used to interact with a new uploaded file to the bucket.
        k = bucket.new_key(generated_name)
        # start Uploading File To The Buket With The Created Key.
        k.set_contents_from_filename(video_path)

        return render(
            request ,
            "upload.html",
            {
                'id_file':new_file.id_file,
                'page':'upload'
            }
        )
    return render(
        request ,
        "upload.html",
        {
            'page':'upload'
        }
    )

@login_required(login_url='/auth/login')
def transcript_status(request, id_file):
    try:
        transcript = Transcripts.objects.get(file_org=File.objects.get(id_file=id_file))
        if transcript.path_srt_fr and transcript.path_srt_es and transcript.path_srt_en:
            # If all three transcript paths are present, return the transcripts as a JSON response
            return JsonResponse({
                'status': 2,
                'detail':'Transcript Found With All Info',
                'message': 'Your file Has Been processed Complety.',
                'transcript': TranscriptsSerializer(transcript).data
            })
        else:
            # If the transcripts are still being processed, start the task and return a message
            return JsonResponse({
                'status': 1,
                'detail': 'Transcript Founded With Initial Creation',
                'message': 'Please wait, your file is processing Right Now.',
                'transcript': TranscriptsSerializer(transcript).data
                })
    except Transcripts.DoesNotExist:
        return JsonResponse({
            'status': 0,
            'detail': 'Transcript Not Found',
            'message': 'Please wait, your file is processing Right Now.',
            'transcript': ''
        })

class S3Input(APIView):
    # authentication_classes = [TokenAuthentication]  # Token authentication is required for this view
    # permission_classes = [IsOwnerOrReadOnly]  # Only the owner can modify the File object, others can only read
    def get_object(self, id):
        """
        Helper method to retrieve a File object by UUID in name.
        """
        # Returns the File object with the given uuid contains in video_path
        try:
            return File.objects.get(video_path__contains=id)
        except File.DoesNotExist:
            # Raises 404 error if no Transcripts objects are found
            raise Http404


    def get(self, request):
        """
        Handles GET requests to retrieve all the File objects in the database.
        Returns a JSON response with the serialized data.
        """
        # Retrieves all File objects and returns them in a response
        queryset = File.objects.filter(user=request.user)
        serializer = FileSerializer(queryset, many=True)

        return Response(serializer.data, status.HTTP_200_OK)

    def put(self, request):
        """
        Handles PUT requests to update a File object in the database.
        Expects the request object to have file_s3_url, language, and srt_file fields.
        """
        BASE_S3_URL = 'https://input-transcribe-bucket.s3.us-east-2.amazonaws.com/'
        # Retrieves the file_uuid using the uuid in the request data file_s3_url
        file_uuid = str(request.data.get('file_s3_url')).replace(BASE_S3_URL,'')
        # Retrieves the file language using the language attribute in the request data
        file_lang = str(request.data.get('language'))
        # get file instance based on file_name
        original_file = self.get_object(file_uuid)
        # Retrieves the corresponding File object and updates it with the request data
        file_serializer = FileSerializer(original_file,data=request.data)
        if file_serializer.is_valid(raise_exception=True):
            file_serializer.save()
            # Create A New Transcripts object For The Updated File
            transcript = Transcripts(file_org=original_file)
            if 'en' in file_lang:
                transcript.path_srt_en = request.data.get('srt_file')
            if 'po' in file_lang:
                transcript.path_srt_po = request.data.get('srt_file')
            if 'es' in file_lang:
                transcript.path_srt_es = request.data.get('srt_file')
            if 'fr' in file_lang:
                transcript.path_srt_fr = request.data.get('srt_file')
            transcript.save()
            # Run Celery Task With Transcript ID

            return Response(file_serializer.data, status=status.HTTP_201_CREATED)
        return Response(file_serializer.errors, status=status.HTTP_400_BAD_REQUEST)

class S3Output(APIView):
    # authentication_classes = [TokenAuthentication]  # Token authentication is required for this view
    # permission_classes = [IsOwnerOrReadOnly]  # Only the owner can modify the File object, others can only read
    def get_objects(self):
        # Returns all Transcripts objects
        try:
            return Transcripts.objects.all()
        except Transcripts.DoesNotExist:
            # Raises 404 error if no Transcripts objects are found
            raise Http404

    def get_object(self, id):
        # Returns the Transcripts object with the given file_org id
        try:
            return Transcripts.objects.get(file_org=id)
        except Transcripts.DoesNotExist:
            # Raises 404 error if the Transcripts object is not found
            raise Http404

    def get(self, request):
        # Retrieves all Transcripts objects and returns them in a response
        queryset = self.get_objects()
        serializer = TranscriptsSerializer(queryset, many=True)
        return Response(data=serializer.data, status=status.HTTP_200_OK)

    def put(self, request):
        # Retrieves the file_id using the uuid in the request data
        file_uuid = str(request.data.get('file')).split(".")[0]
        print(file_uuid)
        file_id = File.objects.get(id_file=file_uuid)
        # Retrieves the corresponding Transcripts object and updates it with the request data
        transcript = self.get_object(file_id)
        transcript_serializer = TranscriptsSerializer(transcript, data=request.data)
        if transcript_serializer.is_valid(raise_exception=True):
            transcript_serializer.save()
            return Response(data=transcript_serializer.data, status=status.HTTP_201_CREATED)
        return Response(data=transcript_serializer.errors, status=status.HTTP_400_BAD_REQUEST)


