"""
# XSD Datatypes, IRI Validator, XSD Validator
"""
import re
from urllib.parse import urlparse

import xmlschema
from enum import Enum, unique
from pystrict import strict
from typing import Any

from oldaplib.src.helpers.serializer import serializer


@unique
@serializer
class XsdDatatypes(Enum):
    """
    Enumeration of the supported xsd datatypes:

    - `XsdDatatypes.string` = 'xsd:string'
    - `XsdDatatypes.langString` = 'rdf:langString'
    - `XsdDatatypes.boolean` = 'xsd:boolean'
    - `XsdDatatypes.decimal` = 'xsd:decimal'
    - `XsdDatatypes.float` = 'xsd:float'
    - `XsdDatatypes.double` = 'xsd:double'
    - `XsdDatatypes.duration` = 'xsd:duration'
    - `XsdDatatypes.dateTime` = 'xsd:dateTime'
    - `XsdDatatypes.dateTimeStamp` = 'xsd:dateTimeStamp'
    - `XsdDatatypes.time` = 'xsd:time'
    - `XsdDatatypes.date` = 'xsd:date'
    - `XsdDatatypes.gYearMonth` = 'xsd:gYearMonth'
    - `XsdDatatypes.gYear` = 'xsd:gYear'
    - `XsdDatatypes.gMonthDay` = 'xsd:gMonthDay'
    - `XsdDatatypes.gDay` = 'xsd:gDay'
    - `XsdDatatypes.gMonth` = 'xsd:gMonth'
    - `XsdDatatypes.hexBinary` = 'xsd:hexBinary'
    - `XsdDatatypes.base64Binary` = 'xsd:base64Binary'
    - `XsdDatatypes.anyURI` = 'xsd:anyURI'
    - `XsdDatatypes.QName` = 'xsd:QName'
    - `XsdDatatypes.normalizedString` = 'xsd:normalizedString'
    - `XsdDatatypes.token` = 'xsd:token'
    - `XsdDatatypes.language` = 'xsd:language'
    - `XsdDatatypes.Name` = 'xsd:name'
    - `XsdDatatypes.NCName` = 'xsd:NCName'
    - `XsdDatatypes.NMTOKEN` = 'xsd:NMTOKEN'
    - `XsdDatatypes.ID` = 'xsd:ID'
    - `XsdDatatypes.IDREF` = 'xsd:IDREF'
    - `XsdDatatypes.IDREFS` = 'xsd: IDREFS'
    - `XsdDatatypes.integer` = 'xsd:integer'
    - `XsdDatatypes.nonPositiveInteger` = 'xsd:nonPositiveInteger'
    - `XsdDatatypes.unsignedLong` = 'xsd:unsignedLong'
    - `XsdDatatypes.unsignedInt` = 'xsd:unsignedInt'
    - `XsdDatatypes.unsignedShort` = 'xsd:unsignedShort'
    - `XsdDatatypes.unsignedByte` = 'xsd:unsignedByte'
    - `XsdDatatypes.positiveInteger` = 'xsd:positiveInteger'

    """
    string = 'xsd:string'
    langString = 'rdf:langString'
    boolean = 'xsd:boolean'
    decimal = 'xsd:decimal'
    float = 'xsd:float'
    double = 'xsd:double'
    duration = 'xsd:duration'
    dateTime = 'xsd:dateTime'
    dateTimeStamp = 'xsd:dateTimeStamp'
    time = 'xsd:time'
    date = 'xsd:date'
    gYearMonth = 'xsd:gYearMonth'
    gYear = 'xsd:gYear'
    gMonthDay = 'xsd:gMonthDay'
    gDay = 'xsd:gDay'
    gMonth = 'xsd:gMonth'
    hexBinary = 'xsd:hexBinary'
    base64Binary = 'xsd:base64Binary'
    anyURI = 'xsd:anyURI'
    QName = 'xsd:QName'
    normalizedString = 'xsd:normalizedString'
    token = 'xsd:token'
    language = 'xsd:language'
    name_ = 'xsd:name'
    NCName = 'xsd:NCName'
    NMTOKEN = 'xsd:NMTOKEN'
    ID = 'xsd:ID'
    IDREF = 'xsd:IDREF'
    integer = 'xsd:integer'
    nonPositiveInteger = 'xsd:nonPositiveInteger'
    negativeInteger = 'xsd:negativeInteger'
    long = 'xsd:long'
    int = 'xsd:int'
    short = 'xsd:short'
    byte = 'xsd:byte'
    nonNegativeInteger = 'xsd:nonNegativeInteger'
    unsignedLong = 'xsd:unsignedLong'
    unsignedInt = 'xsd:unsignedInt'
    unsignedShort = 'xsd:unsignedShort'
    unsignedByte = 'xsd:unsignedByte'
    positiveInteger = 'xsd:positiveInteger'

    def __str__(self):
        return self.value

    @property
    def toRdf(self):
        return self.value


@strict
class IriValidator:
    """
    Calls to validate the syntax of an IRI
    """
    @classmethod
    def validate(cls, val: str) -> bool:
        """
        Class method which validates an IRI. Supported are the protocols "http", "https", and "urn"

        :param val: String to be validated as IRI
        :type val: str
        :return: True or False
        """
        try:
            result = urlparse(val)
            match result.scheme:
                case 'http':
                    return True if result.netloc else False
                case 'https':
                    return True if result.netloc else False
                case 'urn':
                    return True if result.path else False
                case _:
                    return False
            #return all([result.scheme, result.netloc])
        except Exception:
            return False

@strict
class XsdValidator:
    """
    Class to validate generic XSD datatypes
    """
    @classmethod
    def validate(cls,
                 datatype: XsdDatatypes,
                 value: Any) -> bool:
        """
        Validate a value against the given xsd datatype. It uses the xmlschema.XMLSchema11 validator.

        :param datatype: The xsd datatype the value should be validated against
        :type datatype: XsdDatatypes
        :param value: A value to be validated
        :return: True or False
        """
        xsd_string = f"""
        <xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema">
            <xsd:element name="tag" type="{datatype.value}"/>
        </xsd:schema>
        """
        namespace = ""
        if datatype == XsdDatatypes.QName:
            parts = str(value).split(':')
            if len(parts) == 2:
                namespace = f"xmlns:{parts[0]}=\"http://dummy.net/dum\""
            else:
                namespace = "xmlns:dummy=\"http://dummy.net/dum\""
        elif datatype == XsdDatatypes.anyURI:
            return IriValidator.validate(value)
        try:
            xsd_validator = xmlschema.XMLSchema11(xsd_string)
            return xsd_validator.is_valid(f"""<?xml version="1.0" encoding="UTF-8"?><tag {namespace}>""" + str(value) + "</tag>")
        except xmlschema.XMLSchemaParseError as e:
            return False


if __name__ == '__main__':
    print(XsdValidator.validate(XsdDatatypes.anyURI, "http://waelo.org/data/gaga#uuu"))
    print(XsdValidator.validate(XsdDatatypes.anyURI, "https://waelo.org/data/gaga#uuu"))
    print(XsdValidator.validate(XsdDatatypes.anyURI, "https://waelo.org/data/gaga#"))
    print(XsdValidator.validate(XsdDatatypes.NMTOKEN, "https://orcid.org/0000-0003-1681-4036"))
    print(XsdValidator.validate(XsdDatatypes.anyURI, "urn:uuid:7e56b6c4-42e5-4a9d-94cf-d6e22577fb4b"))
    print(XsdValidator.validate(XsdDatatypes.anyURI, "waselias"))
