import csv
import os
import requests
import schedule
import threading
import time
from datetime import datetime
from flask import Flask, request, jsonify
import openmeteo_requests
import requests_cache
from retry_requests import retry

app = Flask(__name__)

# Définition des seuils
THRESHOLDS = {
    "dht22_1_temperature": {"min": 0.0, "max": 36.0},  # Température en °C (extérieure)
    "dht22_1_humidity": {"min": 20.0, "max": 85.0},     # Humidité en %
    "dht22_2_temperature": {"min": 0.0, "max": 40.0},  # Température en °C (intérieure)
    "dht22_2_humidity": {"min": 20.0, "max": 85.0},     # Humidité en %
    "ds18b20_1_temperature": {"min": 0.0, "max": 36.0},# Température en °C
    "ds18b20_2_temperature": {"min": 0.0, "max": 36.0},# Température en °C
    "light_intensity": {"min": 0.0, "max": 1000.0},    # Intensité lumineuse en lux
    "weight": {"min": 27.0, "max": 200.0}                # Poids en kg
}
LOG_FILE = "data_base/sensor_data.csv"

def ensure_csv_exists():
    """Crée le fichier CSV avec l'en-tête s'il n'existe pas"""
    if not os.path.exists(LOG_FILE):
        os.makedirs(os.path.dirname(LOG_FILE), exist_ok=True)  # Crée le dossier si besoin
        with open(LOG_FILE, "w", newline="") as f:
            csv.writer(f).writerow(["Timestamp", "Capteur", "Valeur", "Unite", "Anomalie"])

def get_last_anomaly_state(sensor_name):
    """Récupère le dernier état d'anomalie du capteur depuis le CSV."""
    ensure_csv_exists()
    try:
        with open(LOG_FILE, "r") as f:
            reader = csv.reader(f)
            next(reader)  # Skip header
            for row in reversed(list(reader)):  # Lire depuis la fin
                if row[1] == sensor_name:
                    return row[4]  # Colonne "Anomalie"
    except FileNotFoundError:
        pass
    return "NORMAL"

@app.route('/data', methods=['POST'])
def check_sensors():
    ensure_csv_exists()
    data = request.json
    current_anomalies = []  # Toutes les anomalies actuelles
    new_anomalies = []      # Nouvelles anomalies (pas dans le dernier CSV)
    rows_to_write = []

    for key, values in data.items():
        if key in THRESHOLDS:
            value = values.get("value")
            unit = values.get("unit", "")
            min_val = THRESHOLDS[key]["min"]
            max_val = THRESHOLDS[key]["max"]

            is_anomaly = not (min_val <= value <= max_val)
            last_state = get_last_anomaly_state(key)

            # Enregistrer l'état réel dans le CSV
            anomaly_status = "ANOMALIE" if is_anomaly else "NORMAL"
            rows_to_write.append([
                datetime.now().strftime("%Y-%m-%d %H:%M:%S"),
                key,
                value,
                unit,
                anomaly_status
            ])

            # Gestion des messages
            if is_anomaly:
                msg = f"{key}: {value} {unit} hors seuil [{min_val}, {max_val}]"
                current_anomalies.append(msg)
                if last_state != "ANOMALIE":
                    new_anomalies.append(msg)

    # Écrire dans le CSV
    with open(LOG_FILE, "a", newline="") as f:
        csv.writer(f).writerows(rows_to_write)

    # Générer la réponse
    if new_anomalies:
        status = "WARNING"
        message = f"Nouvelles alertes ⚠️: {', '.join(new_anomalies)}"
        if current_anomalies:  # Ajouter les anomalies continues si nécessaire
            message += f" | Anomalies en cours: {', '.join(current_anomalies)}"
    elif current_anomalies:
        status = "OK"
        message = f"Anomalies en cours 🟠: {', '.join(current_anomalies)}"
    else:
        status = "OK"
        message = "✅ Tout est normal"

    return jsonify({"status": status, "details": message})


# - Intégration BEEP/Open-Meteo

BEEP_API_URL = "https://api.beep.nl/api/sensors"
BEEP_API_KEY = "zxwyt3aqxmc2ae6r"  # À remplacer
COORDINATES = (48.8058614, 2.0769055)  # Coordonnées ruche


def get_sunshine_duration():
    """Récupère la durée d'ensoleillement quotidienne"""
    try:
        # Configuration client API
        cache_session = requests_cache.CachedSession('.cache', expire_after=3600)
        retry_session = retry(cache_session, retries=5, backoff_factor=0.2)
        openmeteo = openmeteo_requests.Client(session=retry_session)

        # Appel API
        params = {
            "latitude": COORDINATES[0],
            "longitude": COORDINATES[1],
            "daily": "sunshine_duration",
            "timezone": "Europe/Paris",
            "forecast_days": 1
        }

        response = openmeteo.weather_api("https://api.open-meteo.com/v1/forecast", params=params)[0]
        daily = response.Daily()
        return daily.Variables(0).ValuesAsNumpy()[0]  # Durée en secondes

    except Exception as e:
        app.logger.error(f"Erreur Open-Meteo: {e}")
        return None


def send_sunshine_to_beep():
    """Envoi quotidien des données d'ensoleillement à BEEP"""
    sunshine = get_sunshine_duration()

    if sunshine is not None:
        try:
            payload = {
                "key": BEEP_API_KEY,
                "t_9": round(float(sunshine) / 3600, 2)  # Conversion en heures
            }

            response = requests.post(BEEP_API_URL, json=payload)
            response.raise_for_status()
            app.logger.info(f"Données envoyées à BEEP: {payload}")

        except Exception as e:
            app.logger.error(f"Erreur envoi BEEP: {e}")


def schedule_job():
    """Planifie les tâches récurrentes"""
    schedule.every().day.at("23:55:00").do(send_sunshine_to_beep)

    while True:
        schedule.run_pending()
        time.sleep(60)  # Vérifie toutes les minutes


# ================================================
# Démarrage du serveur avec le scheduler
# ================================================

if __name__ == '__main__':
    # Démarrer le scheduler dans un thread séparé
    scheduler_thread = threading.Thread(target=schedule_job, daemon=True)
    scheduler_thread.start()

    # Démarrer le serveur Flask
    app.run(host='0.0.0.0', port=14000, debug=False)