# meteo/schema.py
from __future__ import annotations

from dataclasses import dataclass
from typing import List

from influxdb_client import InfluxDBClient


@dataclass(frozen=True)
class MeasurementField:
    """
    Représente un champ (_field) d'un measurement InfluxDB.
    """

    name: str
    type: str  # "float", "string", "boolean", "integer", "unsigned"


def list_measurements(client: InfluxDBClient, bucket: str) -> list[str]:
    """
    Retourne la liste des measurements présents dans le bucket donné.

    Utilise le package Flux `schema.measurements`.
    """
    query = f"""
import "influxdata/influxdb/schema"

schema.measurements(bucket: "{bucket}")
"""
    query_api = client.query_api()
    tables = query_api.query(query)

    measurements: set[str] = set()
    for table in tables:
        for record in table.records:
            value = record.get_value()
            if isinstance(value, str):
                measurements.add(value)

    return sorted(measurements)


def list_measurement_fields(
    client: InfluxDBClient,
    bucket: str,
    measurement: str,
) -> list[MeasurementField]:
    """
    Retourne la liste des champs (_field) pour un measurement donné,
    avec leur type InfluxDB (float, string, boolean, integer, unsigned).

    Utilise le package Flux `schema.measurementFieldKeys`.
    """
    query = f"""
import "influxdata/influxdb/schema"

schema.measurementFieldKeys(
  bucket: "{bucket}",
  measurement: "{measurement}",
)
"""
    query_api = client.query_api()
    tables = query_api.query(query)

    fields: dict[str, str] = {}

    for table in tables:
        for record in table.records:
            name = record.get_value()
            type_str = str(record.values.get("type", "unknown"))
            if isinstance(name, str):
                fields[name] = type_str

    return [
        MeasurementField(name=n, type=t)
        for n, t in sorted(fields.items(), key=lambda item: item[0])
    ]


def list_measurement_tag_keys(
    client: InfluxDBClient,
    bucket: str,
    measurement: str,
) -> list[str]:
    """
    Retourne la liste des clés de tags (tag keys) pour un measurement donné.

    Utilise `schema.measurementTagKeys`.
    """
    query = f"""
import "influxdata/influxdb/schema"

schema.measurementTagKeys(
  bucket: "{bucket}",
  measurement: "{measurement}",
)
"""
    query_api = client.query_api()
    tables = query_api.query(query)

    keys: set[str] = set()
    for table in tables:
        for record in table.records:
            value = record.get_value()
            if isinstance(value, str):
                keys.add(value)

    return sorted(keys)


def list_measurement_tag_values(
    client: InfluxDBClient,
    bucket: str,
    measurement: str,
    tag: str,
) -> list[str]:
    """
    Retourne la liste des valeurs possibles pour un tag donné (par exemple
    `entity_id`) sur un measurement donné.

    Utilise `schema.measurementTagValues`.
    """
    query = f"""
import "influxdata/influxdb/schema"

schema.measurementTagValues(
  bucket: "{bucket}",
  measurement: "{measurement}",
  tag: "{tag}",
)
"""
    query_api = client.query_api()
    tables = query_api.query(query)

    values: set[str] = set()
    for table in tables:
        for record in table.records:
            value = record.get_value()
            if isinstance(value, str):
                values.add(value)

    return sorted(values)
