from .object import FedoraObject
from .proxy import FedoraProxy
from .file import FedoraFile
from rdflib import URIRef, Graph


class FedoraWork(FedoraObject):
    def __init__(self, uri):
        super().__init__(uri)
        self.uri = URIRef(uri)
        self.descriptive_metadata = self.__get_descriptive_metadata()
        self._cache = {}
        self.iana_first = self.__get_iana('first')
        self.iana_last = self.__get_iana('last')

    def __get_iana(self, name):
        return next(self.content.objects(subject=self.uri, predicate=URIRef(f"{self.namespaces.iana}{name}")), None)

    def __get_descriptive_metadata(self):
        """Builds a graph with just known descriptive metadata."""
        description = Graph()
        descriptive_predicates = {
            f"{self.namespaces.dc}subject",
            f"{self.namespaces.dc}creator",
            f"{self.namespaces.dc}description",
            f"{self.namespaces.dc}format",
            f"{self.namespaces.dc}language",
            f"{self.namespaces.dc}publisher",
            f"{self.namespaces.dc}title",
            f"{self.namespaces.dc}type",
            f"{self.namespaces.dc}rights",
            f"{self.namespaces.dcterms}alternative",
            f"{self.namespaces.dcterms}created",
            f"{self.namespaces.dcterms}extent",
            f"{self.namespaces.dcterms}isPartOf",
            f"{self.namespaces.dcterms}medium",
            f"{self.namespaces.dcterms}spatial",
        }
        for s, p, o in self.content:
            if str(p) in descriptive_predicates:
                description.add((s, p, o))
        return description

    def __get_cached(self, key, func):
        """Helper to cache expensive operations."""
        if key not in self._cache:
            self._cache[key] = func()
        return self._cache[key]

    @property
    def rights(self):
        return self.__get_cached('rights', lambda: self.__get_first_literal(f"{self.namespaces.dc}rights"))

    @property
    def title(self):
        return self.__get_cached('title', lambda: self.__get_all_literals(f"{self.namespaces.dc}title"))

    @property
    def summary(self):
        return self.__get_cached('summary', lambda: self.__get_first_literal(f"{self.namespaces.dc}description"))

    @property
    def members(self):
        return self.__get_cached('members', lambda: self.__get_all_objects(f"{self.namespaces.pcdm}hasMember"))

    def __get_first_literal(self, predicate):
        for _, p, o in self.content:
            if str(p) == predicate:
                return str(o)
        return ""

    def __get_all_literals(self, predicate):
        return [str(o) for _, p, o in self.content if str(p) == predicate]

    def __get_all_objects(self, predicate):
        return [str(o) for _, p, o in self.content if str(p) == predicate]

    def get_ordered_members(self):
        ordered_members = []
        current = FedoraProxy(uri=str(self.iana_first))
        while current:
            ordered_members.append(current.get_proxy_for())
            if current.has_iana_next:
                current = FedoraProxy(uri=str(current.get_next()))
            else:
                current = None
        return ordered_members

    def get_ordered_member_files(self):
        ordered_members = []
        current = FedoraProxy(uri=str(self.iana_first))
        while current:
            current_part = FedoraFile(uri=str(current.get_proxy_for()))
            current_part_files = current_part.get_files()
            for current_file in current_part_files:
                ordered_members.append(str(current_file))
            if current.has_iana_next:
                current = FedoraProxy(uri=str(current.get_next()))
            else:
                current = None
        return ordered_members

    def get_members(self):
        return list(self.content.objects(
            subject=URIRef(self.uri), predicate=URIRef(f"{self.namespaces.pcdm}hasMember")
        ))

    def metadata_to_dict(self):
        description = {}
        for _, p, o in self.content:
            p_str = str(p)
            if p_str.startswith(self.namespaces.dc):
                key = f"dc_{p_str[len(self.namespaces.dc):]}"
            elif p_str.startswith(self.namespaces.dcterms):
                key = f"dcterms_{p_str[len(self.namespaces.dcterms):]}"
            elif p_str.startswith(self.namespaces.fedora):
                key = f"fedora_{p_str[len(self.namespaces.fedora):]}"
            elif p_str.startswith(self.namespaces.ebucore):
                key = f"ebucore_{p_str[len(self.namespaces.ebucore):]}"
            elif p_str.startswith(self.namespaces.ldp):
                key = f"ldp_{p_str[len(self.namespaces.ldp):]}"
            elif p_str.startswith(self.namespaces.premis):
                key = f"premis_{p_str[len(self.namespaces.premis):]}"
            elif p_str.startswith(self.namespaces.relations):
                key = f"relations_{p_str[len(self.namespaces.relations):]}"
            elif p_str.startswith(self.namespaces.tamudigital):
                key = f"tamudigital_{p_str[len(self.namespaces.tamudigital):]}"
            elif p_str.startswith(self.namespaces.tamulocal):
                key = f"tamulocal_{p_str[len(self.namespaces.tamulocal):]}"
            elif p_str.startswith(self.namespaces.title):
                key = f"title_{p_str[len(self.namespaces.title):]}"
            elif p_str.startswith(self.namespaces.schemaorg):
                key = f"schema_{p_str[len(self.namespaces.schemaorg):]}"
            elif p_str.startswith(self.namespaces.rights):
                key = f"rights_{p_str[len(self.namespaces.rights):]}"
            elif p_str.startswith(self.namespaces.subject):
                key = f"subject_{p_str[len(self.namespaces.subject):]}"
            elif p_str.startswith(self.namespaces.identifier):
                key = f"identifier_{p_str[len(self.namespaces.identifier):]}"
            elif p_str.startswith(self.namespaces.identifiertwo):
                key = f"identifiertwo_{p_str[len(self.namespaces.identifiertwo):]}"
            elif p_str.startswith(self.namespaces.foaf):
                key = f"foaf_{p_str[len(self.namespaces.foaf):]}"
            elif p_str.startswith(self.namespaces.bibframe):
                key = f"bibframe_{p_str[len(self.namespaces.bibframe):]}"
            elif p_str.startswith(self.namespaces.oretwo):
                key = f"oretwo_{p_str[len(self.namespaces.oretwo):]}"
            else:
                continue
            description.setdefault(key, []).append(str(o))
        return description


if __name__ == '__main__':
    x = FedoraWork(
        'https://api.library.tamu.edu/fcrepo/rest/3b/6f/c3/25/3b6fc325-f6ca-41d8-b91e-8c5db3be8c13/london-collection_objects/9'
    )

