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.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("auth:login")
        transcripts = Transcripts.objects.filter(file_org__user=request.user)
        context = {
            "transcripts":transcripts,
            "page":"allTranscripts"
        }
        
        return render(request,'dashboard.html',context)


@login_required(login_url='/auth/login')
def upload(request):
    if request.method == 'POST':
        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]
        file_id = File.objects.get(video_path__contains=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)
    

