<?php
/**
 * Maintenance GENIUS - Uptime Monitoring
 * Surveillance du site avec notifications email
 * Version 2.9.126
 * 
 * Fonctionne indépendamment du mode maintenance.
 * Utilise WP-Cron pour les vérifications périodiques.
 */

if (!defined('ABSPATH')) {
    exit;
}

class MG_Monitoring {

    /**
     * Nom du cron event
     */
    const CRON_HOOK = 'mg_monitoring_check';

    /**
     * Option pour stocker l'historique des événements
     */
    const EVENTS_OPTION = 'mg_monitoring_events';

    /**
     * Option pour stocker le statut actuel
     */
    const STATUS_OPTION = 'mg_monitoring_status';

    /**
     * Limite d'événements conservés
     */
    const MAX_EVENTS = 100;

    /**
     * Initialise le module monitoring
     */
    public static function init() {
        add_filter('cron_schedules', [__CLASS__, 'add_cron_schedules']);

        add_action(self::CRON_HOOK, [__CLASS__, 'run_check']);

        add_action('admin_init', [__CLASS__, 'manage_cron']);

        register_deactivation_hook(MG_PLUGIN_FILE, [__CLASS__, 'deactivate_cron']);
    }

    /**
     * Ajoute les intervalles de cron personnalisés
     * @param array $schedules
     * @return array
     */
    public static function add_cron_schedules($schedules) {
        $schedules['mg_every_2min'] = [
            'interval' => 120,
            'display'  => __('Every 2 minutes', 'maintenance-genius'),
        ];
        $schedules['mg_every_5min'] = [
            'interval' => 300,
            'display'  => __('Every 5 minutes', 'maintenance-genius'),
        ];
        $schedules['mg_every_10min'] = [
            'interval' => 600,
            'display'  => __('Every 10 minutes', 'maintenance-genius'),
        ];
        $schedules['mg_every_15min'] = [
            'interval' => 900,
            'display'  => __('Every 15 minutes', 'maintenance-genius'),
        ];
        $schedules['mg_every_30min'] = [
            'interval' => 1800,
            'display'  => __('Every 30 minutes', 'maintenance-genius'),
        ];
        return $schedules;
    }

    /**
     * Gère l'activation/désactivation du cron selon les paramètres
     */
    public static function manage_cron() {
        $settings = MG_Settings::load();
        $monitoring_enabled = !empty($settings['monitoring_enabled']);
        $has_cron = wp_next_scheduled(self::CRON_HOOK);

        if ($monitoring_enabled && !$has_cron) {
            $interval = self::get_cron_interval($settings);
            wp_schedule_event(time(), $interval, self::CRON_HOOK);
        } elseif (!$monitoring_enabled && $has_cron) {
            wp_clear_scheduled_hook(self::CRON_HOOK);
        } elseif ($monitoring_enabled && $has_cron) {
            $current_schedule = wp_get_schedule(self::CRON_HOOK);
            $desired_interval = self::get_cron_interval($settings);
            if ($current_schedule !== $desired_interval) {
                wp_clear_scheduled_hook(self::CRON_HOOK);
                wp_schedule_event(time(), $desired_interval, self::CRON_HOOK);
            }
        }
    }

    /**
     * Retourne l'identifiant d'intervalle cron selon les settings
     * @param array $settings
     * @return string
     */
    private static function get_cron_interval($settings) {
        $interval_minutes = intval($settings['monitoring_interval'] ?? 5);
        $map = [
            2  => 'mg_every_2min',
            5  => 'mg_every_5min',
            10 => 'mg_every_10min',
            15 => 'mg_every_15min',
            30 => 'mg_every_30min',
        ];
        return $map[$interval_minutes] ?? 'mg_every_5min';
    }

    /**
     * Désactive le cron (appelé à la désactivation du plugin)
     */
    public static function deactivate_cron() {
        wp_clear_scheduled_hook(self::CRON_HOOK);
    }

    /**
     * Exécute une vérification de disponibilité du site
     * Appelé par WP-Cron ou manuellement
     */
    public static function run_check() {
        $settings = MG_Settings::load();

        if (empty($settings['monitoring_enabled'])) {
            return;
        }

        $url = home_url('/');
        $timeout = 10;

        // Hook: Permet aux addons de modifier l'URL ou le timeout (v2.9.44)
        $url     = apply_filters('mg_monitoring_check_url', $url, $settings);
        $timeout = apply_filters('mg_monitoring_check_timeout', $timeout, $settings);

        $start_time = microtime(true);

        $response = wp_remote_get($url, [
            'timeout'   => $timeout,
            'sslverify' => false,
            'headers'   => [
                'User-Agent' => 'Maintenance-GENIUS-Monitor/' . MG_VERSION,
            ],
        ]);

        $response_time = round((microtime(true) - $start_time) * 1000); // ms

        $is_down = false;
        $status_code = 0;
        $error_message = '';

        if (is_wp_error($response)) {
            $is_down = true;
            $error_message = $response->get_error_message();
        } else {
            $status_code = wp_remote_retrieve_response_code($response);

            $maintenance_active = !empty($settings['maintenance_enabled']);

            if ($status_code === 0) {
                $is_down = true;
                $error_message = __('No response from server', 'maintenance-genius');
            } elseif ($status_code === 503 && $maintenance_active) {
                // Vérifier si c'est la page de maintenance du plugin ou un vrai 503 serveur
                $body = wp_remote_retrieve_body($response);
                if (stripos($body, 'maintenance-container') !== false) {
                    $is_down = false; // C'est notre page de maintenance → OK
                } else {
                    $is_down = true;  // Vrai 503 serveur → alerte !
                    $error_message = sprintf(
                        /* translators: %d: count/number */
                        __('HTTP %d response (not from Maintenance GENIUS)', 'maintenance-genius'),
                        $status_code
                    );
                }
            } elseif ($status_code >= 500) {
                $is_down = true;
                $error_message = sprintf(
                    /* translators: %d: count/number */
                    __('HTTP %d response', 'maintenance-genius'),
                    $status_code
                );
            }
        }

        $prev_status = get_option(self::STATUS_OPTION, [
            'is_down'    => false,
            'since'      => '',
            'last_check' => '',
            'last_code'  => 200,
        ]);

        $now = current_time('mysql');
        $status_changed = ($is_down !== (bool) $prev_status['is_down']);

        $new_status = [
            'is_down'        => $is_down,
            'since'          => $status_changed ? $now : ($prev_status['since'] ?? $now),
            'last_check'     => $now,
            'last_code'      => $status_code,
            'response_time'  => $response_time, // TTFB en ms (v2.9.44)
            'error_message'  => $error_message,
        ];

        // Hook: Permet aux addons d'enrichir le statut (ex: SSL check, disk space) (v2.9.44)
        $new_status = apply_filters('mg_monitoring_status_data', $new_status, $response, $settings);

        update_option(self::STATUS_OPTION, $new_status);

        // Hook: Déclenché après chaque check — idéal pour stocker TTFB, logs étendus (v2.9.44)
        do_action('mg_monitoring_after_check', $new_status, $prev_status, $response, $settings);

        if ($status_changed) {
            self::log_event($is_down, $status_code, $error_message, $now);

            // Hook: Déclenché lors d'un changement de statut (v2.9.44)
            do_action('mg_monitoring_status_changed', $new_status, $prev_status, $settings);

            if (self::can_send_notification($settings)) {
                self::send_notification($is_down, $status_code, $error_message, $settings);
                update_option('mg_monitoring_last_notification', time());
            }
        }
    }

    /**
     * Vérifie si on peut envoyer une notification (cooldown anti-spam)
     * @param array $settings
     * @return bool
     */
    private static function can_send_notification($settings) {
        $cooldown = intval($settings['monitoring_email_cooldown'] ?? 5) * 60;
        $last_sent = get_option('mg_monitoring_last_notification', 0);
        return (time() - $last_sent) >= $cooldown;
    }

    /**
     * Enregistre un événement dans l'historique
     * @param bool $is_down
     * @param int $status_code
     * @param string $error_message
     * @param string $datetime
     */
    private static function log_event($is_down, $status_code, $error_message, $datetime) {
        $events = get_option(self::EVENTS_OPTION, []);

        $events[] = [
            'type'         => $is_down ? 'down' : 'up',
            'status_code'  => $status_code,
            'error'        => $error_message,
            'datetime'     => $datetime,
            'timestamp'    => current_time('timestamp'),
        ];

        if (count($events) > self::MAX_EVENTS) {
            $events = array_slice($events, -self::MAX_EVENTS);
        }

        update_option(self::EVENTS_OPTION, $events);
    }

    /**
     * Envoie les notifications email
     * @param bool $is_down
     * @param int $status_code
     * @param string $error_message
     * @param array $settings
     */
    private static function send_notification($is_down, $status_code, $error_message, $settings) {
        $emails_raw = $settings['monitoring_emails'] ?? '';
        if (empty($emails_raw)) {
            return;
        }

        $emails = self::parse_emails($emails_raw);
        if (empty($emails)) {
            return;
        }

        $site_name = get_bloginfo('name');
        $site_url  = home_url('/');
        $now       = current_time('d/m/Y H:i:s');

        $placeholders = [
            '{site_name}'   => $site_name,
            '{site_url}'    => $site_url,
            '{status_code}' => $status_code,
            '{error}'       => $error_message,
            '{datetime}'    => $now,
            '{down_since}'  => $now,
        ];

        if ($is_down) {
            $subject = $settings['monitoring_subject_down'] ?? '';
            $body    = $settings['monitoring_body_down'] ?? '';

            if (empty($subject)) {
                $subject = sprintf(
                    /* translators: %s: site name */
                    __('⚠️ [%s] Site is DOWN', 'maintenance-genius'),
                    $site_name
                );
            }
            if (empty($body)) {
                $body = sprintf(
                    /* translators: 1: site name, 2: site url, 3: status code, 4: error message, 5: datetime */
                    __("Your site %1\$s (%2\$s) appears to be offline.\n\nHTTP Status: %3\$s\nError: %4\$s\nDetected: %5\$s\n\n— Maintenance GENIUS Monitoring", 'maintenance-genius'),
                    $site_name, $site_url, $status_code, $error_message, $now
                );
            }
        } else {
            $subject = $settings['monitoring_subject_up'] ?? '';
            $body    = $settings['monitoring_body_up'] ?? '';

            if (empty($subject)) {
                $subject = sprintf(
                    /* translators: %s: site name */
                    __('✅ [%s] Site is back ONLINE', 'maintenance-genius'),
                    $site_name
                );
            }
            if (empty($body)) {
                $body = sprintf(
                    /* translators: 1: site name, 2: site url, 3: datetime */
                    __("Your site %1\$s (%2\$s) is back online.\n\nRecovered: %3\$s\n\n— Maintenance GENIUS Monitoring", 'maintenance-genius'),
                    $site_name, $site_url, $now
                );
            }
        }

        $subject = strtr($subject, $placeholders);
        $body    = strtr($body, $placeholders);

        $headers = ['Content-Type: text/plain; charset=UTF-8'];

        foreach ($emails as $email) {
            wp_mail($email, $subject, $body, $headers);
        }
    }

    /**
     * Parse une string d'emails (un par ligne ou virgule)
     * @param string $raw
     * @return array
     */
    public static function parse_emails($raw) {
        if (is_array($raw)) {
            $raw = implode("\n", $raw);
        }
        $raw = str_replace([',', ';'], "\n", $raw);
        $lines = explode("\n", $raw);
        $emails = [];

        foreach ($lines as $line) {
            $email = trim($line);
            if (is_email($email)) {
                $emails[] = $email;
            }
        }

        return array_unique($emails);
    }

    /**
     * Récupère le statut actuel du monitoring
     * @return array
     */
    public static function get_status() {
        return get_option(self::STATUS_OPTION, [
            'is_down'       => false,
            'since'         => '',
            'last_check'    => '',
            'last_code'     => 0,
            'error_message' => '',
        ]);
    }

    /**
     * Récupère l'historique des événements
     * @param int $limit
     * @return array
     */
    public static function get_events($limit = 50) {
        $events = get_option(self::EVENTS_OPTION, []);
        $events = array_reverse($events);
        return array_slice($events, 0, $limit);
    }

    /**
     * Vide l'historique des événements
     * @return bool
     */
    public static function clear_events() {
        return delete_option(self::EVENTS_OPTION);
    }

    /**
     * Exécute un test de vérification immédiat (via AJAX)
     * @return array
     */
    public static function test_check() {
        $url = home_url('/');
        $settings = MG_Settings::load();
        $maintenance_active = !empty($settings['maintenance_enabled']);

        $start_time = microtime(true);

        $response = wp_remote_get($url, [
            'timeout'   => 10,
            'sslverify' => false,
            'headers'   => [
                'User-Agent' => 'Maintenance-GENIUS-Monitor/' . MG_VERSION,
            ],
        ]);

        $response_time = round((microtime(true) - $start_time) * 1000); // ms

        if (is_wp_error($response)) {
            return [
                'status'        => 'down',
                'code'          => 0,
                'message'       => $response->get_error_message(),
                'response_time' => $response_time,
                'time'          => current_time('d/m/Y H:i:s'),
            ];
        }

        $code = wp_remote_retrieve_response_code($response);

        $is_down = false;
        if ($code === 0) {
            $is_down = true;
        } elseif ($code === 503 && $maintenance_active) {
            // Vérifier si c'est la page de maintenance du plugin ou un vrai 503 serveur
            $body = wp_remote_retrieve_body($response);
            if (stripos($body, 'maintenance-container') !== false) {
                $is_down = false; // C'est notre page de maintenance → OK
            } else {
                $is_down = true;  // Vrai 503 serveur → alerte !
            }
        } elseif ($code >= 500) {
            $is_down = true;
        }

        $status_label = $is_down ? 'down' : 'up';
        $message = wp_remote_retrieve_response_message($response);
        if ($code === 503 && $maintenance_active && !$is_down) {
            $message = __('503 (Maintenance mode active — OK)', 'maintenance-genius');
        }

        return [
            'status'        => $status_label,
            'code'          => $code,
            'message'       => $message,
            'response_time' => $response_time,
            'time'          => current_time('d/m/Y H:i:s'),
        ];
    }

    /**
     * Envoie un email de test
     * @param array $settings
     * @return array
     */
    public static function send_test_email($settings) {
        $emails = self::parse_emails($settings['monitoring_emails'] ?? '');

        if (empty($emails)) {
            return [
                'success' => false,
                'message' => __('No valid email addresses configured.', 'maintenance-genius'),
            ];
        }

        $site_name = get_bloginfo('name');
        $subject = sprintf(
            /* translators: %s: site name */
            __('🔔 [%s] Monitoring test notification', 'maintenance-genius'),
            $site_name
        );
        $body = sprintf(
            /* translators: 1: site name, 2: site url, 3: datetime */
            __("This is a test notification from Maintenance GENIUS Monitoring.\n\nSite: %1\$s (%2\$s)\nDate: %3\$s\n\nIf you received this email, monitoring notifications are working correctly.\n\n— Maintenance GENIUS Monitoring", 'maintenance-genius'),
            $site_name, home_url('/'), current_time('d/m/Y H:i:s')
        );

        $headers = ['Content-Type: text/plain; charset=UTF-8'];
        $sent = 0;
        $failed = 0;

        foreach ($emails as $email) {
            if (wp_mail($email, $subject, $body, $headers)) {
                $sent++;
            } else {
                $failed++;
            }
        }

        return [
            'success' => $sent > 0,
            'message' => sprintf(
                /* translators: 1: sent count, 2: total count */
                __('Test email sent to %1$d/%2$d recipients.', 'maintenance-genius'),
                $sent, $sent + $failed
            ),
        ];
    }

    /**
     * Retourne les infos pour le futur endpoint REST API (v2.8.0+)
     * Prêt pour le dashboard centralisé TTB
     * @return array
     */
    public static function get_api_data() {
        $status = self::get_status();
        $events = self::get_events(20);
        $settings = MG_Settings::load();

        $data = [
            'site_url'    => home_url('/'),
            'site_name'   => get_bloginfo('name'),
            'monitoring'  => !empty($settings['monitoring_enabled']),
            'interval'    => intval($settings['monitoring_interval'] ?? 5),
            'status'      => $status,
            'events'      => $events,
            'plugin_ver'  => MG_VERSION,
        ];

        // Hook: Permet aux addons d'enrichir les données API (v2.9.44)
        return apply_filters('mg_monitoring_api_data', $data, $settings);
    }
}
