import os
from rdflib import Graph, URIRef
from rest_framework.generics import ListCreateAPIView, RetrieveUpdateDestroyAPIView, ListAPIView
from rest_framework import permissions

from django.http import HttpResponse, JsonResponse
from django.views.decorators.csrf import csrf_exempt
from rest_framework.parsers import JSONParser

from reqman.apps.reqtool.models.requirements import Prefix, Boilerplate, BoilerplateGroup, PREFIX_CHOICES, LOGIC_CONNECTIVE
from reqman.apps.reqtool.models.requirements import BoilerplateData, InferenceResults, BoilerplateGroupClassesInstances

from reqman.apps.reqtool.rest_api.serializers.requirements import BoilerplateSerializer, PrefixSerializer, BoilerplateDataSerializer, BoilerplateGroupSerializer, InferSerializer, BoilerplateGroupClassesInstancesSerializer
from reqman.apps.permissions import IsOwnerOrReadOnly

from reqman.apps.reqtool.models.main_req import Main
from reqman.apps.reqtool.models.suffix_req import Suffix
from reqman.apps.reqtool.rest_api.services import fuseki, inference

from rest_framework.response import Response
from rest_framework.views import APIView
from rest_framework.exceptions import APIException

from django.shortcuts import get_object_or_404
import requests, json
from requests.auth import HTTPBasicAuth
from reqman.settings.environment import env



class OntologiesChoicesViewSet(APIView):
    '''Get current Ontologies from Fuseki server'''

    def get(self, request):
        data={'datasets':''}
        try : 
            url = requests.get(env("FUSEKI_URL")+"/$/datasets", auth = HTTPBasicAuth(env("FUSEKI_Username"), env("FUSEKI_Password")))
            text = url.text
            data = json.loads(text)
        except:
            pass
        list_ontology=['/Default']
        for i in data['datasets'] :
            list_ontology.append(i['ds.name'])
        ONTOLOGIES_CHOICES = tuple((str(n), str(n)) for n in (list_ontology))
        response = Response(ONTOLOGIES_CHOICES)
        return response


class BoilerplateGroupCreateAPIView(ListCreateAPIView):
    """
    API view to retrieve list of posts or create new
    """
    permission_classes = [permissions.IsAuthenticatedOrReadOnly]
    serializer_class = BoilerplateGroupSerializer


    def get_queryset(self):
        queryset_boil = BoilerplateGroup.objects.filter(boilerplate_owner = self.request.user)
        return queryset_boil

    #Custom actions when POST
    def perform_create(self, serializer):
        serializer.save(boilerplate_owner=self.request.user)

class BoilerplateGroupList(ListAPIView):
    """
    API view to retrieve list of posts based on title of Boilerplate
    """
    permission_classes = [permissions.IsAuthenticatedOrReadOnly]
    serializer_class = BoilerplateGroupSerializer
    queryset = BoilerplateGroup.objects.all()
    

class BoilerplateGroupDetailsAPIView(RetrieveUpdateDestroyAPIView):
    """
    API view to retrieve, update or delete post
    """
    permission_classes = [permissions.IsAuthenticatedOrReadOnly]
    serializer_class = BoilerplateGroupSerializer
    queryset = BoilerplateGroup.objects.all()

    #Custom actions when PUT
    def perform_update(self, serializer):
        instance = serializer.save()

    #Custom actions when DELETE
    def perform_destroy(self, instance):
        try:
            os.system('rm -rf ../../Ontologies/' + instance.title_bgroup +'/')
        except:
            print('No file exist')
        instance.delete()


class BoilerplateListCreateAPIView(ListCreateAPIView):
    """
    API view to retrieve list of posts or create new
    """
    permission_classes = [permissions.IsAuthenticatedOrReadOnly]
    serializer_class = BoilerplateSerializer

    def get_queryset(self):
        group_gb = self.kwargs['groupboil']
        queryset_boil = Boilerplate.objects.filter(owner = self.request.user, group_of_boilerplate = group_gb)
        return queryset_boil

    #Custom actions when POST
    def perform_create(self, serializer):
        serializer.save(owner=self.request.user)


class BoilerplateList(ListAPIView):
    """
    API view to retrieve list of posts based on title of Boilerplate
    """
    permission_classes = [permissions.IsAuthenticatedOrReadOnly]
    serializer_class = BoilerplateSerializer


    def get_queryset(self):
        group_gb = self.kwargs['groupboil']
        title = self.kwargs['title_1']
        queryset_title = Boilerplate.objects.filter(title = title, group_of_boilerplate = group_gb)
        return queryset_title

   

class BoilerplateDetailsAPIView(RetrieveUpdateDestroyAPIView):
    """
    API view to retrieve, update or delete post
    """
    permission_classes = [permissions.IsAuthenticatedOrReadOnly,
                      IsOwnerOrReadOnly]
    serializer_class = BoilerplateSerializer
    queryset = Boilerplate.objects.all()

    #Custom actions when PUT
    def perform_update(self, serializer):
        instance = serializer.validated_data
        bd_title = instance['title']
        BoilerplateData.objects.filter(boilerplate_data_id=self.kwargs['pk'], group_of_boilerplate_data = instance['group_of_boilerplate']).update(title_data = bd_title)
        instance = serializer.save()
        

    #Custom actions when DELETE
    def perform_destroy(self, instance):
        #boildata = BoilerplateData.objects.filter(boilerplate_data_id=self.kwargs['pk'])
        #data = BoilerplateGroupClassesInstances.objects.filter(classes_instances_owner= boildata.values('owner_data')[0]['owner_data'], classes_instances_group_of_boilerplate = boildata.values('group_of_boilerplate_data')[0]['group_of_boilerplate_data'])
        #g = Graph()
        #g.load(data.values('ontology_file')[0]['ontology_file'], format="turtle")
        #rdo_instance= URIRef("http://delab.csd.auth.gr/ontologies/2018/RDO-instances#" + boildata.values('title_data')[0]['title_data'])
        #g.remove((rdo_instance, None, None))
        #g.remove((None, None, rdo_instance))
        #prefix = Prefix.objects.filter(prefix_boilerplate = instance)
        #pre_instance= URIRef("http://delab.csd.auth.gr/ontologies/2018/RDO-instances#" + boildata.values('title_data')[0]['title_data'] +'_'+ prefix.values('simple_prefix')[0]['simple_prefix'])
        #g.remove((pre_instance, None, None))
        #g.remove((None, None, pre_instance))
        #main = Main.objects.filter(boilerplate_of_main = instance)
        #rdo_instance= URIRef("http://delab.csd.auth.gr/ontologies/2018/RDO-instances#" + boildata.values('title_data')[0]['title_data'] +'_'+ main.values('main_choices')[0]['main_choices'])
        #g.remove((rdo_instance, None, None))
        #g.remove((None, None, rdo_instance))
        #g.serialize(data.values('ontology_file')[0]['ontology_file'], format='turtle')
        instance.delete()


class PrefixListAPIView(ListAPIView):
    """
    API view to retrieve list of posts or create new
    """
    permission_classes = [permissions.IsAuthenticatedOrReadOnly]
    serializer_class = PrefixSerializer

    def get_queryset(self):
        group_pk = self.kwargs['boilerplate']
        queryset_prefix = Prefix.objects.filter(prefix_boilerplate = group_pk)
        return queryset_prefix

class PrefixDetailsAPIView(RetrieveUpdateDestroyAPIView):
    """
    API view to retrieve, update or delete post
    """
    permission_classes = [permissions.IsAuthenticatedOrReadOnly]
    serializer_class = PrefixSerializer

    def get_queryset(self):
        group_pk = self.kwargs['boilerplate']
        queryset_prefix = Prefix.objects.filter(prefix_boilerplate = group_pk)
        return queryset_prefix

    #Custom actions when PUT
    def perform_update(self, serializer):
        instance = serializer.validated_data
        #add data in thn Model BoilerplateData
        quantifier_instance,numunit_instance  = [[""], [""]]
        numinstance=''
        es_instance = instance['system_fun_item'].rsplit(':', 1)
        ev_instance =instance['state_or_verb'].rsplit(':', 1)
        ei_instance = instance['item_function_flow_statevalue'].rsplit(':', 1)      
        if instance['prefix_quantifier']:
            quantifier_instance = instance['prefix_quantifier'].rsplit(':', 1)
        if instance['prefix_mumerical_units']:
            numunit_instance = instance['prefix_mumerical_units'].rsplit(':', 1)  
        if instance['prefix_numerical']:
            numinstance= instance['prefix_numerical']
        pr = (instance['prefix'] + ' ' + es_instance[len(es_instance)-1] + ' ' + ev_instance[len(ev_instance)-1] + ' ' + quantifier_instance[len(quantifier_instance)-1] +' '+numinstance +' ' + numunit_instance[len(numunit_instance)-1]  + ' ' + ei_instance[len(ei_instance)-1])
        boildata = BoilerplateData.objects.filter(owner_data=instance['prefix_boilerplate'].owner, boilerplate_data_id = instance['prefix_boilerplate'])
        #get instances of the ontology that this boilerplate belongs
        data = BoilerplateGroupClassesInstances.objects.filter(classes_instances_owner= instance['prefix_boilerplate'].owner, classes_instances_group_of_boilerplate = boildata.values('group_of_boilerplate_data')[0]['group_of_boilerplate_data'])
        es_data = data.values('system_choices')[0]['system_choices'] + data.values('function_choices')[0]['function_choices'] + data.values('item_choices')[0]['item_choices']
        if( instance['system_fun_item'] not in es_data):
            raise APIException("PREFIX : Instance of Subject does not exist")
        ev_data = data.values('state_choices')[0]['state_choices'] + data.values('prefix_verb_choices')[0]['prefix_verb_choices']
        if( instance['state_or_verb'] not in ev_data):
            raise APIException("PREFIX : Instance of State or Verb does not exist")
        quantifier_data = data.values('quantifier_choices')[0]['quantifier_choices']
        if( instance['prefix_quantifier'] not in quantifier_data):
            raise APIException("MAIN : Instance of Quantifier does not exist")
        numunit_data = data.values('number_unit_choices')[0]['number_unit_choices']
        if( instance['prefix_mumerical_units'] not in numunit_data):
            raise APIException("MAIN : Instance of Number Unit does not exist")
        ei_data = data.values('function_choices')[0]['function_choices'] + data.values('item_choices')[0]['item_choices']+ data.values('flow_choices')[0]['flow_choices']+ data.values('state_value_choices')[0]['state_value_choices']
        if( instance['item_function_flow_statevalue'] not in ei_data):
            raise APIException("PREFIX : Instance of Object does not exist")
        #find the class of the prefix
        ontology_file = data.values('ontology_file')[0]['ontology_file']
        prefix_choices = inference.getclassofprefix(instance, ontology_file)
        if prefix_choices[0] == 'ERROR':
            raise APIException("Prefix choices not in [P1-P3]")
        else:
            boildata.update(prefix_data = pr )
            serializer.save(simple_prefix = prefix_choices)


    #Custom actions when DELETE
    def perform_destroy(self, instance):
        instance = serializer.validated_data
        instance.delete()



class BoilerplateDataListAPIView(ListAPIView):
    """
    API view to retrieve list of posts or create new
    """
    permission_classes = [permissions.IsAuthenticatedOrReadOnly]
    serializer_class = BoilerplateDataSerializer

    def get_queryset(self):
        group_gb = self.kwargs['groupboil']
        queryset_boil_data = BoilerplateData.objects.filter(owner_data = self.request.user, group_of_boilerplate_data = group_gb)
        return queryset_boil_data


class InferListAPIView(ListAPIView):
    """
    API view to retrieve list of posts or create new
    """
    permission_classes = [permissions.IsAuthenticatedOrReadOnly]
    serializer_class = InferSerializer

    def get_queryset(self):
        group_pk = self.kwargs['groupboil']
        queryset_infer = InferenceResults.objects.filter(infer_group_of_boilerplate = group_pk)
        return queryset_infer

class InferDetailsAPIView(RetrieveUpdateDestroyAPIView):
    """
    API view to retrieve, update or delete post
    """
    permission_classes = [permissions.IsAuthenticatedOrReadOnly]
    serializer_class = InferSerializer

    def get_queryset(self):
        group_pk = self.kwargs['groupboil']
        queryset_infer = InferenceResults.objects.filter(infer_group_of_boilerplate = group_pk)
        return queryset_infer

    #Custom actions when PUT
    def perform_update(self, serializer):
        instance = serializer.validated_data
        project_title = ""
        boildata= []
        prefixdata = []
        maindata = []
        suffixdata = []
        project_title =  instance['infer_group_of_boilerplate'].title_bgroup
        prefix = BoilerplateData.objects.filter(group_of_boilerplate_data = instance['infer_group_of_boilerplate'].id)
        for id in prefix:
            boildata.append(self.getboildata(id.boilerplate_data_id.id))
            prefixdata.append(self.getprefixdata(id.boilerplate_data_id.id))
            maindata.append(self.getmaindata(id.boilerplate_data_id.id))
            suffixdata.append(self.getsuffixdata(id.boilerplate_data_id.id))
        #try:
        metrics, onto_file = inference.inferencing(instance['ontology_file'], project_title, boildata, prefixdata, maindata, suffixdata)
        #except:
        #    raise APIException("Not all instances in the Ontology")
        instance.update(inference_data = metrics, ontology_file=onto_file)
        serializer.save()
    
    def getboildata(self, pr):
        return (Boilerplate.objects.filter(id = pr))
    
    def getprefixdata(self, pr):
        return (Prefix.objects.filter(prefix_boilerplate = pr))

    def getmaindata(self, pr):
        return (Main.objects.filter(boilerplate_of_main = pr))
    
    def getsuffixdata(self, pr):
        return (Suffix.objects.filter(boilerplate_of_suffix = pr))


class PrefixChoicesViewSet(ListAPIView):
    """
    API view to retrieve list of Prefix choices
    """
    permission_classes = [permissions.IsAuthenticatedOrReadOnly]
    serializer_class = BoilerplateGroupClassesInstancesSerializer

    def get_queryset(self):
        group_pk = self.kwargs['groupboil']
        queryset_cl= BoilerplateGroupClassesInstances.objects.filter(classes_instances_group_of_boilerplate = group_pk)
        return queryset_cl


import mimetypes

class GetOntology(APIView):
    serializer_class = BoilerplateGroupClassesInstances

    def get(self, request, groupboil, format=None):
        data = BoilerplateGroupClassesInstances.objects.filter(classes_instances_group_of_boilerplate = groupboil)
        filename =  data.values('ontology_file')[0]['ontology_file'] + 'infer.ttl'
        filepath = data.values('ontology_file')[0]['ontology_file']+'infer.ttl'
        try :
            path = open(filepath, 'r')
        except:
            raise APIException("Fail to download ontology file")
            # Set the mime type
        mime_type, _ = mimetypes.guess_type(filepath)
        # Set the return value of the HttpResponse
        response = HttpResponse(path, content_type=mime_type)
        # Set the HTTP header for sending to browser
        response['Content-Disposition'] = "attachment; filename=%s" % filename
        # Return the response value
        return response
        