import pathlib
from typing import Iterator
import pandas as pd
from ted_sws.resources.prefixes import PREFIXES_DEFINITIONS
import re

CONCEPTUAL_MAPPINGS_RULES_SHEET_NAME = "Rules"
RULES_SF_FIELD_ID = 'Standard Form Field ID (M)'
RULES_SF_FIELD_NAME = 'Standard Form Field Name (M)'
RULES_E_FORM_BT_ID = 'eForm BT-ID (O)'
RULES_E_FORM_BT_NAME = 'eForm BT Name (O)'
RULES_BASE_XPATH = 'Base XPath (for anchoring) (M)'
RULES_FIELD_XPATH = 'Field XPath (M)'
RULES_CLASS_PATH = 'Class path (M)'
RULES_PROPERTY_PATH = 'Property path (M)'

DEFAULT_RQ_NAME = 'sparql_query_'

SPARQL_PREFIX_PATTERN = re.compile('(?:\\s+|^)(\\w+)?:')
SPARQL_PREFIX_LINE = 'PREFIX {prefix}: <{value}>'


def get_sparql_prefixes(sparql_q: str) -> set:
    finds: list = re.findall(SPARQL_PREFIX_PATTERN, sparql_q)
    return set(finds)


def sparql_validation_generator(data: pd.DataFrame) -> Iterator[str]:
    """
        This function generates SPARQL queries based on data in the dataframe.
    :param data:
    :return:
    """
    for index, row in data.iterrows():
        sf_field_id = row[RULES_SF_FIELD_ID]
        sf_field_name = row[RULES_SF_FIELD_NAME]
        e_form_bt_id = row[RULES_E_FORM_BT_ID]
        e_form_bt_name = row[RULES_E_FORM_BT_NAME]
        base_xpath = row[RULES_BASE_XPATH]
        field_xpath = row[RULES_FIELD_XPATH]
        class_path = row[RULES_CLASS_PATH]
        property_path = row[RULES_PROPERTY_PATH]
        prefixes = [SPARQL_PREFIX_LINE.format(
            prefix=prefix, value=PREFIXES_DEFINITIONS.get(prefix)
        ) for prefix in get_sparql_prefixes(property_path)]
        yield f"#title: {sf_field_id} - {sf_field_name}\n" \
              f"#description: “{sf_field_id} - {sf_field_name}” in SF corresponds to “{e_form_bt_id} {e_form_bt_name}” in eForms. The corresponding XML element is {base_xpath}{field_xpath}. The expected ontology instances are epo: {class_path} .\n" \
              "\n" + "\n".join(prefixes) + "\n\n" \
                                           f"ASK WHERE {{ {property_path} }}"


def mapping_suite_processor_generate_sparql_queries(conceptual_mappings_file_path: pathlib.Path,
                                                    output_sparql_queries_folder_path: pathlib.Path,
                                                    rq_name: str = DEFAULT_RQ_NAME):
    """
        This function reads data from conceptual_mappings.xlsx and generates SPARQL validation queries in provided package.
    :param conceptual_mappings_file_path:
    :param output_sparql_queries_folder_path:
    :param rq_name:
    :return:
    """
    with open(conceptual_mappings_file_path, 'rb') as excel_file:
        conceptual_mappings_rules_df = pd.read_excel(excel_file, sheet_name=CONCEPTUAL_MAPPINGS_RULES_SHEET_NAME)
        conceptual_mappings_rules_df.columns = conceptual_mappings_rules_df.iloc[0]
        conceptual_mappings_rules_df = conceptual_mappings_rules_df[1:]
        conceptual_mappings_rules_df = conceptual_mappings_rules_df[
            conceptual_mappings_rules_df[RULES_PROPERTY_PATH].notnull()]
    sparql_queries = sparql_validation_generator(conceptual_mappings_rules_df)
    output_sparql_queries_folder_path.mkdir(parents=True, exist_ok=True)
    for index, sparql_query in enumerate(sparql_queries):
        output_file_path = output_sparql_queries_folder_path / f"{rq_name}{index}.rq"
        with open(output_file_path, "w") as output_file:
            output_file.write(sparql_query)

[((19, 24, 19, 56), 're.compile', 're.compile', ({(19, 35, 19, 55): '"""(?:\\\\s+|^)(\\\\w+)?:"""'}, {}), "('(?:\\\\s+|^)(\\\\w+)?:')", False, 'import re\n'), ((24, 18, 24, 61), 're.findall', 're.findall', ({(24, 29, 24, 50): 'SPARQL_PREFIX_PATTERN', (24, 52, 24, 60): 'sparql_q'}, {}), '(SPARQL_PREFIX_PATTERN, sparql_q)', False, 'import re\n'), ((63, 39, 63, 113), 'pandas.read_excel', 'pd.read_excel', (), '', True, 'import pandas as pd\n'), ((44, 33, 44, 65), 'ted_sws.resources.prefixes.PREFIXES_DEFINITIONS.get', 'PREFIXES_DEFINITIONS.get', ({(44, 58, 44, 64): 'prefix'}, {}), '(prefix)', False, 'from ted_sws.resources.prefixes import PREFIXES_DEFINITIONS\n')]