/**
 * Service exécuté en arrière-plan pour tenter d'envoyer des notifications périodiques,
 * comme un rappel du meilleur score ou un rappel d'inactivité.
 *
 * <p><strong>AVERTISSEMENT IMPORTANT :</strong> Ce service utilise un {@link android.os.Handler}
 * pour planifier les tâches répétitives. Cette approche est simple mais <strong>NON FIABLE</strong>
 * pour les tâches en arrière-plan sur les versions modernes d'Android. Le système peut tuer
 * le service à tout moment pour économiser les ressources, et le redémarrage via
 * {@code START_STICKY} n'est pas garanti d'être rapide ou même de se produire sur tous les appareils
 * ou dans toutes les conditions (ex: mode Doze, restrictions fabricant). </p>
 *
 * <p><strong>Pour une solution robuste et recommandée par Android pour les tâches périodiques
 * en arrière-plan, il est FORTEMENT conseillé d'utiliser {@link androidx.work.WorkManager}.</strong>
 * WorkManager gère les contraintes (réseau, charge), la persistance des tâches et
 * garantit leur exécution même si l'application ou l'appareil redémarre.</p>
 *
 * <p>Ce code est fourni à titre d'exemple de la logique de notification, mais le mécanisme
 * de planification devrait être remplacé par WorkManager en production.</p>
 */
package legion.muyue.best2048;

import android.app.Service;
import android.content.Intent;
import android.content.SharedPreferences;
import android.os.Handler;
import android.os.IBinder;
import android.os.Looper; // Important pour créer un Handler sur le Main Thread
import android.util.Log;

import androidx.annotation.Nullable;
import java.util.concurrent.TimeUnit;

public class NotificationService extends Service {

    /** Tag pour les logs spécifiques à ce service. */
    private static final String TAG = "NotificationService";

    // --- Constantes de Notification et Intervalles ---
    /** ID unique pour la notification de rappel du meilleur score. */
    private static final int NOTIFICATION_ID_HIGHSCORE = 2; // Doit être différent des autres notifs (ex: 1 pour achievement)
    /** ID unique pour la notification de rappel d'inactivité. */
    private static final int NOTIFICATION_ID_INACTIVITY = 3;

    /** Intervalle minimum souhaité entre deux notifications de rappel du meilleur score (ex: 1 jour). */
    private static final long HIGHSCORE_INTERVAL_MS = TimeUnit.DAYS.toMillis(1);
    /** Seuil d'inactivité : durée après laquelle une notification d'inactivité peut être envoyée (ex: 3 jours). */
    private static final long INACTIVITY_THRESHOLD_MS = TimeUnit.DAYS.toMillis(3);
    /** Intervalle minimum souhaité entre deux notifications de rappel d'inactivité (ex: 1 jour, pour éviter spam si toujours inactif). */
    private static final long INACTIVITY_NOTIFICATION_COOLDOWN_MS = TimeUnit.DAYS.toMillis(1);

    /** Intervalle auquel le Handler vérifie s'il faut envoyer une notification (ex: toutes les 6 heures). */
    // NOTE: Avec WorkManager, cette vérification fréquente serait inutile, on planifierait directement la tâche au bon moment.
    private static final long CHECK_INTERVAL_MS = TimeUnit.HOURS.toMillis(6);

    /** Handler pour poster les tâches Runnable périodiques. Fonctionne sur le thread principal. */
    private Handler handler;
    /** Runnable contenant la logique de vérification et d'envoi des notifications. */
    private Runnable periodicTaskRunnable;

    // --- Constantes SharedPreferences ---
    // (Doivent correspondre à celles utilisées dans MainActivity et GameStats)
    /** Nom du fichier de préférences partagées. */
    private static final String PREFS_NAME = "Best2048_Prefs";
    /** Clé pour lire le meilleur score global. */
    private static final String HIGH_SCORE_KEY = "high_score";
    /** Clé pour lire le timestamp de la dernière partie jouée. */
    private static final String LAST_PLAYED_TIME_KEY = "last_played_time";
    /** Clé pour vérifier si les notifications sont activées par l'utilisateur. */
    private static final String NOTIFICATIONS_ENABLED_KEY = "notifications_enabled";
    /** Clé pour stocker le timestamp du dernier envoi de la notification High Score. */
    private static final String LAST_HS_NOTIFICATION_TIME = "lastHsNotificationTime";
    /** Clé pour stocker le timestamp du dernier envoi de la notification d'Inactivité. */
    private static final String LAST_INACTIVITY_NOTIFICATION_TIME = "lastInactivityNotificationTime";

    /**
     * Appelée par le système lors de la première création du service.
     * Initialise le Handler et le Runnable pour la tâche périodique.
     * Ne crée PAS le canal de notification ici, car MainActivity le fait déjà.
     */
    @Override
    public void onCreate() {
        super.onCreate();
        Log.i(TAG, "onCreate: Service de notification en cours de création.");
        // Utilise le Looper principal pour le Handler. Simple, mais bloque le thread principal
        // si checkAndSendNotifications() devient une tâche longue.
        // Pour des tâches potentiellement longues, utiliser un HandlerThread serait mieux.
        handler = new Handler(Looper.getMainLooper());

        // Définit le Runnable qui sera exécuté périodiquement
        periodicTaskRunnable = new Runnable() {
            @Override
            public void run() {
                Log.d(TAG, "Exécution de la tâche périodique de vérification des notifications.");
                // Vérifie s'il faut envoyer des notifications
                checkAndSendNotifications();
                // Replanifie la prochaine exécution de cette même tâche
                // ATTENTION: Ce mécanisme n'est pas fiable en arrière-plan.
                handler.postDelayed(this, CHECK_INTERVAL_MS);
                Log.d(TAG, "Prochaine vérification des notifications planifiée dans " + CHECK_INTERVAL_MS + " ms.");
            }
        };
    }

    /**
     * Appelée lorsque le service est démarré, soit par `startService()` soit après un redémarrage du système
     * (si START_STICKY est utilisé et que le système choisit de le redémarrer).
     * Lance la tâche périodique de vérification des notifications.
     *
     * @param intent L'Intent fourni à startService(), peut être null si redémarré par le système.
     * @param flags Indicateurs supplémentaires sur la demande de démarrage.
     * @param startId Un identifiant unique représentant cette demande de démarrage spécifique.
     * @return La valeur de retour indique comment le système doit gérer le service s'il est tué.
     * {@code START_STICKY} : Le système essaiera de recréer le service après l'avoir tué,
     * mais l'Intent ne sera pas redélivré (il sera null).
     * <strong>NOTE: START_STICKY n'est pas une garantie d'exécution fiable pour les tâches
     * périodiques en arrière-plan. Utilisez WorkManager.</strong>
     */
    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        Log.i(TAG, "onStartCommand: Service démarré (ou redémarré). StartId: " + startId);

        // S'assure qu'il n'y a pas d'anciennes tâches en double avant de poster la nouvelle
        handler.removeCallbacks(periodicTaskRunnable);
        // Lance la première exécution de la tâche immédiatement (ou presque)
        handler.post(periodicTaskRunnable);
        Log.d(TAG, "Première vérification des notifications postée.");

        // Utiliser START_STICKY pour que le système essaie de redémarrer le service s'il est tué.
        // C'est un pis-aller par rapport à WorkManager.
        return START_STICKY;
    }

    /**
     * Appelée lorsque le service est sur le point d'être détruit.
     * Nettoie les ressources, en particulier, arrête la planification des tâches
     * périodiques via le Handler pour éviter les fuites ou les exécutions non désirées.
     */
    @Override
    public void onDestroy() {
        super.onDestroy();
        Log.i(TAG, "onDestroy: Service de notification en cours de destruction.");
        // Arrête la planification des tâches lorsque le service est détruit
        if (handler != null && periodicTaskRunnable != null) {
            Log.d(TAG, "Annulation des tâches périodiques planifiées.");
            handler.removeCallbacks(periodicTaskRunnable);
        }
        // Autres nettoyages si nécessaire
    }

    /**
     * Retourne l'interface de communication au client.
     * Comme c'est un service démarré (Started Service) et non lié (Bound Service),
     * cette méthode retourne {@code null}.
     *
     * @param intent L'Intent qui a été utilisé pour se lier au service (non pertinent ici).
     * @return null car ce service ne permet pas le binding.
     */
    @Nullable
    @Override
    public IBinder onBind(Intent intent) {
        // Ce service n'est pas conçu pour être lié.
        return null;
    }

    /**
     * Vérifie les conditions pour envoyer les notifications périodiques (High Score, Inactivité).
     * Lit les préférences utilisateur (notifications activées?) et les timestamps nécessaires.
     * Appelle les méthodes d'affichage de notification appropriées si les conditions et
     * les délais depuis le dernier envoi sont respectés.
     * Met à jour le timestamp du dernier envoi après avoir tenté d'envoyer une notification.
     */
    private void checkAndSendNotifications() {
        Log.d(TAG, "checkAndSendNotifications: Début de la vérification.");
        SharedPreferences prefs = getSharedPreferences(PREFS_NAME, MODE_PRIVATE);

        // 1. Vérifier si les notifications sont globalement activées par l'utilisateur
        boolean notificationsEnabled = prefs.getBoolean(NOTIFICATIONS_ENABLED_KEY, false); // Lire la préférence
        if (!notificationsEnabled) {
            Log.i(TAG, "checkAndSendNotifications: Notifications désactivées dans les préférences, arrêt de la vérification.");
            // Si les notifications sont désactivées, on pourrait arrêter le service pour économiser des ressources.
            // stopSelf(); // Arrêterait le service lui-même.
            return;
        }

        long currentTime = System.currentTimeMillis();

        // 2. Vérification pour la notification High Score
        long lastHsNotificationTime = prefs.getLong(LAST_HS_NOTIFICATION_TIME, 0);
        if (currentTime - lastHsNotificationTime > HIGHSCORE_INTERVAL_MS) {
            Log.d(TAG, "checkAndSendNotifications: Intervalle pour notification High Score écoulé.");
            int highScore = prefs.getInt(HIGH_SCORE_KEY, 0);
            if (highScore > 0) { // N'envoie pas si le high score est 0
                Log.i(TAG, "checkAndSendNotifications: Envoi de la notification High Score.");
                showHighScoreNotificationNow(highScore);
                // Met à jour le timestamp du dernier envoi APRÈS avoir tenté d'envoyer
                prefs.edit().putLong(LAST_HS_NOTIFICATION_TIME, currentTime).apply();
            } else {
                Log.d(TAG, "checkAndSendNotifications: High Score est 0, notification non envoyée.");
            }
        } else {
            Log.d(TAG, "checkAndSendNotifications: Intervalle pour notification High Score non écoulé.");
        }

        // 3. Vérification pour la notification d'Inactivité
        long lastPlayedTime = prefs.getLong(LAST_PLAYED_TIME_KEY, 0);
        long lastInactivityNotificationTime = prefs.getLong(LAST_INACTIVITY_NOTIFICATION_TIME, 0);

        // Condition 1: Temps depuis la dernière partie > Seuil d'inactivité
        boolean isInactivityThresholdMet = (lastPlayedTime > 0 && currentTime - lastPlayedTime > INACTIVITY_THRESHOLD_MS);
        // Condition 2: Temps depuis la dernière notification d'inactivité > Cooldown
        boolean isCooldownMet = (currentTime - lastInactivityNotificationTime > INACTIVITY_NOTIFICATION_COOLDOWN_MS);

        if (isInactivityThresholdMet) {
            Log.d(TAG, "checkAndSendNotifications: Seuil d'inactivité atteint.");
            if (isCooldownMet) {
                Log.i(TAG, "checkAndSendNotifications: Cooldown pour notification d'inactivité respecté. Envoi...");
                showInactivityNotificationNow();
                // Met à jour le timestamp du dernier envoi APRÈS avoir tenté d'envoyer
                prefs.edit().putLong(LAST_INACTIVITY_NOTIFICATION_TIME, currentTime).apply();
            } else {
                Log.d(TAG, "checkAndSendNotifications: Cooldown pour notification d'inactivité non écoulé.");
            }
        } else {
            Log.d(TAG, "checkAndSendNotifications: Seuil d'inactivité non atteint.");
        }
        Log.d(TAG, "checkAndSendNotifications: Fin de la vérification.");
    }

    /**
     * Prépare et affiche immédiatement la notification de rappel du meilleur score.
     * Utilise {@link NotificationHelper} pour l'affichage effectif.
     *
     * @param highScore Le meilleur score à afficher dans la notification.
     */
    private void showHighScoreNotificationNow(int highScore) {
        String title = getString(R.string.notification_title_highscore);
        String message = getString(R.string.notification_text_highscore, highScore);
        NotificationHelper.showNotification(this, title, message, NOTIFICATION_ID_HIGHSCORE);
    }

    /**
     * Prépare et affiche immédiatement la notification de rappel d'inactivité.
     * Utilise {@link NotificationHelper} pour l'affichage effectif.
     */
    private void showInactivityNotificationNow() {
        String title = getString(R.string.notification_title_inactivity);
        String message = getString(R.string.notification_text_inactivity);
        NotificationHelper.showNotification(this, title, message, NOTIFICATION_ID_INACTIVITY);
    }

}