'''Module containing Handlers for the Publication Documentation'''

from django.dispatch import receiver
from django.db.models.signals import post_delete

from rdmo.projects.models import Value
from rdmo.options.models import Option
from rdmo.domain.models import Attribute

from ..config import BASE_URI, endpoint
from ..getters import get_items, get_mathmoddb, get_mathalgodb, get_properties, get_questions
from ..helpers import value_editor
from ..queries import query_sparql
from ..adders import add_basics, add_references, add_relations_flexible

from .constants import (
    INDEX_COUNTERS,
    PROPS,
    RELATANT_URIS,
    RELATION_URIS,
    PUBLICATIONS,
    LANGUAGES,
    JOURNALS,
    AUTHORS
)
from .utils import generate_label
from .sparql import queryPublication
from .models import Publication

class Information:
    '''Class containing functions, querying external sources for specific
       entities and integrating the related metadata into the questionnaire.'''

    def __init__(self):
        '''Load shared data once'''
        self.questions = get_questions('publication')
        self.mathalgodb = get_mathalgodb()
        self.mathmoddb = get_mathmoddb()
        self.base = BASE_URI

    def citation(self, instance):
        '''Citation Information'''

        # Publication specific Questions.
        publication = self.questions["Publication"]

        # Stop if no Text or 'not found' in ID Field
        if not instance.text or instance.text == 'not found':
            return

        # Get Source and ID of selected Publication
        source, identifier = instance.external_id.split(':')

        # Empty Data as Fallback
        data = {}

        # If Publication from MathAlgoDB...
        if source == 'mathalgodb':
            #...query the MathAlgoDB,...
            query = queryPublication['PublicationMathAlgoDB'].format(
                identifier
            )
            results = query_sparql(
                query,
                endpoint['mathalgodb']['sparql']
            )

            if not results:
                return

            #...structure the data...
            data = Publication.from_query(results)

            #...and add the Information to the Questionnaire.
            add_basics(
                project = instance.project,
                text = instance.text,
                questions = self.questions,
                item_type = 'Publication',
                index = (instance.set_index, None)
            )

            add_references(
                project = instance.project,
                data = data,
                uri = f'{BASE_URI}{publication["Reference"]["uri"]}',
                set_index = instance.set_index
            )

        # If Publication from MaRDI Portal...
        elif source == 'mardi':
            #...query the MaRDI Portal,...
            query = queryPublication['MaRDI']['QID_FULL'].format(
                identifier,
                **get_items(),
                **get_properties()
            )
            results = query_sparql(
                query,
                endpoint['mardi']['sparql']
            )

            if not results:
                return

            #...structure the data...
            data = Publication.from_query(results)

            #...and add the Information to the Questionnaire.
            if str(instance.project.catalog).endswith('mardmo-algorithm-catalog'):
                value_editor(
                    project = instance.project,
                    uri = f'{BASE_URI}{publication["Name"]["uri"]}',
                    info = {
                        'text': generate_label(data), 
                        'set_index': instance.set_index
                    }
                )
            else:
                value_editor(
                    project = instance.project,
                    uri = f'{BASE_URI}{publication["Name"]["uri"]}',
                    info = {
                        'text': data.label, 
                        'set_index': instance.set_index
                    }
                )

            value_editor(
                project = instance.project,
                uri = f'{BASE_URI}{publication["Description"]["uri"]}',
                info = {
                    'text': data.description, 
                    'set_index': instance.set_index
                }
            )

            add_references(
                project = instance.project,
                data = data,
                uri = f'{BASE_URI}{publication["Reference"]["uri"]}',
                set_index = instance.set_index
            )

        # If Publication from Wikidata...
        elif source == 'wikidata':
            #...query Wikidata,...
            query = queryPublication['Wikidata']['QID_FULL'].format(
                identifier
            )
            results = query_sparql(
                query,
                endpoint['wikidata']['sparql-scholarly']
            )

            if not results:
                return

            #...structure the data...
            data = Publication.from_query(results)

            #and add the Information to the Questionnaire.
            if str(instance.project.catalog).endswith('mardmo-algorithm-catalog'):
                value_editor(
                    project = instance.project,
                    uri = f'{BASE_URI}{publication["Name"]["uri"]}',
                    info = {
                        'text': generate_label(data), 
                        'set_index': instance.set_index
                    }
                )
            else:
                value_editor(
                    project = instance.project,
                    uri = f'{BASE_URI}{publication["Name"]["uri"]}',
                    info = {
                        'text': data.label, 
                        'set_index': instance.set_index
                    }
                )

            value_editor(
                project = instance.project,
                uri = f'{BASE_URI}{publication["Description"]["uri"]}',
                info = {
                    'text': data.description, 
                    'set_index': instance.set_index
                }
            )

            add_references(
                project = instance.project,
                data = data,
                uri = f'{BASE_URI}{publication["Reference"]["uri"]}',
                set_index = instance.set_index
            )

        if data:

            # For Models add Relations
            if str(instance.project.catalog).endswith('mardmo-model-catalog'):
                if source == 'mardi':
                    add_relations_flexible(
                        project = instance.project,
                        data = data,
                        props = {
                            'keys': PROPS['P2E'],
                            'mapping': self.mathmoddb,
                        },
                        index = {
                            'set_prefix': instance.set_index
                        },
                        statement = {
                            'relation': f'{BASE_URI}{publication["P2E"]["uri"]}',
                            'relatant': f'{BASE_URI}{publication["EntityRelatant"]["uri"]}',
                        },
                    )

            # For Algorithms add Relations
            if str(instance.project.catalog).endswith('mardmo-algorithm-catalog'):
                if source == 'mathalgodb':
                    add_relations_flexible(
                        project = instance.project,
                        data = data,
                        props = {
                            'keys': PROPS['P2A'],
                            'mapping': self.mathalgodb,
                        },
                        index = {
                            'set_prefix': instance.set_index
                        },
                        statement = {
                            'relation': f'{BASE_URI}{publication["P2A"]["uri"]}',
                            'relatant': f'{BASE_URI}{publication["ARelatant"]["uri"]}',
                        },
                    )

                    for prop in PROPS['P2BS']:
                        for value in getattr(data, prop):
                            value_editor(
                                project = instance.project,
                                uri = f'{BASE_URI}{publication[RELATION_URIS[value.item_class]]["uri"]}',
                                info = {
                                    'option': Option.objects.get(uri = self.mathalgodb[prop]),
                                    'set_index': INDEX_COUNTERS[value.item_class],
                                    'set_prefix': instance.set_index
                                }
                            )
                            value_editor(
                                project = instance.project,
                                uri = f'{BASE_URI}{publication[RELATANT_URIS[value.item_class]]["uri"]}',
                                info = {
                                    'text': f"{value.label} ({value.description}) [mathalgodb]",
                                    'external_id': value.id,
                                    'set_index': INDEX_COUNTERS[value.item_class],
                                    'set_prefix': instance.set_index
                                }
                            )
                            INDEX_COUNTERS[value.item_class] += 1
        return

@receiver(post_delete, sender=Value)
def publication_delete(sender, **kwargs):
    '''Handler to delete hidden Publication Information
       upon deletion of Set.
    '''
    instance = kwargs.get("instance", None)
    # Get Questions of Publication Section
    questions = get_questions('publication')
    # Check if Publication is concerned
    if instance and instance.attribute.uri == f'{BASE_URI}{questions["Publication"]["uri"]}':
        # Get Project, Snapshot and Index of Deleted Set
        set_index = instance.set_index
        project = instance.project
        snapshot = instance.snapshot
        # Loop through "hidden" Data and delete it
        for key in PUBLICATIONS | LANGUAGES | JOURNALS | AUTHORS:
            Value.objects.filter(
                attribute_id = Attribute.objects.get(
                    uri = f'{BASE_URI}{questions["Publication"][key]["uri"]}'
                ),
                set_index = set_index,
                project = project,
                snapshot = snapshot
            ).delete()
