"""Class to retrieve query placeholder resources

note: this is not the correct place for this class - it should be cmem_client or cmempy
"""

from __future__ import annotations

import json
from typing import TYPE_CHECKING

from cmem_client.models.query_catalog import Query

if TYPE_CHECKING:
    from cmem_client.client import Client

FETCH_PLACEHOLDERS = """
PREFIX shui: <https://vocab.eccenca.com/shui/>
PREFIX rdfs: <http://www.w3.org/2000/01/rdf-schema#>

SELECT ?iri ?label ?comment ?key ?datatype ?valueQueryText
FROM <{{graph}}>
WHERE {
  ?iri a shui:QueryPlaceholder ;
    shui:QueryPlaceholder_key ?key ;
    rdfs:label ?label ;
    shui:QueryPlaceholder_usedInQuery <{{query}}> .
  OPTIONAL {
    ?iri shui:QueryPlaceholder_valueQuery ?vq .
    ?vq shui:queryText ?valueQueryText .
  }
  OPTIONAL {
    ?iri shui:QueryPlaceholder_datatype ?datatype .
  }
  OPTIONAL {
    ?iri rdfs:comment ?comment .
  }
}
"""


class QueryPlaceholder:
    """A query placeholder"""

    key: str
    label: str
    comment: str | None
    datatype: str | None
    value_query: str | None
    client: Client

    def __init__(  # noqa: PLR0913
        self,
        key: str,
        label: str,
        client: Client,
        comment: str | None = None,
        datatype: str | None = None,
        value_query: str | None = None,
    ):
        self.key = key
        self.label = label
        self.comment = comment
        self.datatype = datatype
        self.value_query = value_query
        self.client = client

    def complete(
        self,
        incomplete: str = "",  # noqa: ARG002
        provided_params: dict[str, str] | None = None,
    ) -> list[str] | list[tuple[str, str]]:
        """Prepare a list of placeholder values"""
        if self.value_query is None:
            return []
        value_query = Query(text=self.value_query)
        needed_keys = value_query.get_placeholder_keys()
        if not needed_keys.issubset(set(provided_params or {})):
            return []
        query_text = value_query.fill_placeholders(provided_params or {})
        raw = self.client.queries.execute_query(
            query_text, accept="application/sparql-results+json"
        )
        result = json.loads(raw)
        projection_vars = result["head"]["vars"]
        bindings: list[dict] = result["results"]["bindings"]
        if "value" not in projection_vars:
            return []

        if "description" not in projection_vars:
            return [str(_["value"]["value"]) for _ in bindings]

        values_with_description = []
        for _ in bindings:
            value = str(_["value"]["value"])
            description = _.get("description", {}).get("value", "")
            values_with_description.append((value, description))
        return values_with_description


def get_placeholders_for_query(
    client: Client, iri: str, catalog_graph: str | None = None
) -> dict[str, QueryPlaceholder]:
    """Get a placeholder dict for a query"""
    graph = catalog_graph or "https://ns.eccenca.com/data/queries/"
    query_text = FETCH_PLACEHOLDERS.replace("{{graph}}", graph).replace("{{query}}", iri)
    raw = client.queries.execute_query(query_text, accept="application/sparql-results+json")
    results = json.loads(raw)
    placeholders = {}
    for binding in results["results"]["bindings"]:
        key = binding["key"]["value"]
        placeholders[key] = QueryPlaceholder(
            key=key,
            label=binding["label"]["value"],
            comment=binding.get("comment", {}).get("value"),
            datatype=binding.get("datatype", {}).get("value"),
            value_query=binding.get("valueQueryText", {}).get("value"),
            client=client,
        )
    return placeholders
