"""
Tool 2 — Données de loyers observés (Observatoire des Loyers 2025).
Interroge la table 'loyers' de la base MySQL.
"""

from __future__ import annotations

import json
import logging

import pymysql

from domain.db import get_db

logger = logging.getLogger("tools.get_loyer_data")


def get_loyer_data(parametre: str) -> dict | list:
    """
    Retourne les données de loyers observés pour l'agglomération de Toulouse.

    Paramètre JSON (tous les champs sont optionnels) :
        {
          "zone":                "Ville centre",  # ou "Périphérie"
          "type_habitat":        "Appartement",   # ou "Maison"
          "nombre_pieces":       "Appart 2P",     # voir valeurs ci-dessous
          "epoque_construction": "3. Entre 1971-1990",
          "anciennete_locataire": "1. Moins de 1 an"
        }

    Valeurs valides pour nombre_pieces :
        Appart 1P, Appart 2P, Appart 3P, Appart 4P+
        Maison 1-3P, Maison 4P+
        Ensemble 1P, Ensemble 2P, Ensemble 3P, Ensemble 4P+

    Sans paramètre → retourne les statistiques globales toute agglomération.

    Retour : liste de lignes correspondantes (dict), ou dict {"erreur": ...}.
    """
    try:
        params = json.loads(parametre) if parametre and parametre.strip() else {}
    except (json.JSONDecodeError, TypeError):
        params = {}

    zone                 = (params.get("zone")                or "").strip() or None
    type_habitat         = (params.get("type_habitat")        or "").strip() or None
    nombre_pieces        = (params.get("nombre_pieces")       or "").strip() or None
    epoque_construction  = (params.get("epoque_construction") or "").strip() or None
    anciennete_locataire = (params.get("anciennete_locataire")or "").strip() or None

    def _build_where(cols_vals: list[tuple[str, str | None]]) -> tuple[str, list]:
        conditions, values = [], []
        for col, val in cols_vals:
            if val is not None:
                conditions.append(f"{col} = ?")
                values.append(val)
            else:
                conditions.append(f"{col} IS NULL")
        return " AND ".join(conditions), values

    _COLS = [
        "zone", "type_habitat", "epoque_construction",
        "anciennete_locataire", "nombre_pieces",
        "loyer_m2_moyen", "loyer_m2_median", "loyer_m2_q1", "loyer_m2_q3",
        "loyer_mensuel_moyen", "loyer_mensuel_median", "loyer_mensuel_q1", "loyer_mensuel_q3",
        "surface_moyenne", "nombre_observations", "nombre_logements",
    ]
    _SELECT = "SELECT " + ", ".join(_COLS) + " FROM loyers"

    filter_pairs = [
        ("zone", zone), ("type_habitat", type_habitat),
        ("nombre_pieces", nombre_pieces), ("epoque_construction", epoque_construction),
        ("anciennete_locataire", anciennete_locataire),
    ]

    where, values = _build_where(filter_pairs)
    sql = f"{_SELECT} WHERE {where} ORDER BY nombre_observations DESC"

    logger.info("get_loyer_data — SQL : %s", sql.strip()[:200])

    try:
        with get_db() as conn:
            rows = conn.execute(sql, values).fetchall()
    except pymysql.Error as exc:
        logger.error("Erreur SQL : %s", exc)
        return {"erreur": f"Erreur SQL : {exc}"}

    if not rows:
        # No exact match — relax IS NULL constraints, keep only non-null filters
        logger.info("Aucun résultat exact — tentative sans contraintes IS NULL.")
        loose_pairs = [(col, val) for col, val in filter_pairs if val is not None]
        if not loose_pairs:
            return {"erreur": "Aucune donnée trouvée pour ces critères."}

        loose_where = " AND ".join(f"{col} = ?" for col, _ in loose_pairs)
        loose_values = [val for _, val in loose_pairs]
        sql_loose = f"{_SELECT} WHERE {loose_where} ORDER BY nombre_observations DESC"

        try:
            with get_db() as conn:
                rows = conn.execute(sql_loose, loose_values).fetchall()
        except pymysql.Error as exc:
            return {"erreur": f"Erreur SQL : {exc}"}

    # DictCursor already returns list[dict]
    logger.info("get_loyer_data → %d ligne(s) retournée(s).", len(rows))

    if len(rows) == 1:
        return {"source": "Observatoire des Loyers 2025 — Agglomération de Toulouse", **rows[0]}

    return {
        "source":    "Observatoire des Loyers 2025 — Agglomération de Toulouse",
        "resultats": rows,
    }
