<?php
/**
 * Classe de configuration pour EdenPersona for WooCommerce – Customer Insights & Analytics
 *
 * Cette classe centralise la gestion des constantes, options et paramètres
 * par défaut du plugin.
 *
 * @package EdenPersona_Connector_Analytics
 * @since 1.0.0
 */

if ( ! defined( 'ABSPATH' ) ) {
    exit; // Exit if accessed directly.
}

class EDENPERSONA_Config {

    // ========================================
    // CONSTANTES D'OPTIONS WORDPRESS
    // ========================================

    /**
     * Option pour le token API
     */
    const OPTION_TOKEN = 'edenpersona_api_token';

    /**
     * Option pour la dernière synchronisation
     */
    const OPTION_LAST_SYNC = 'edenpersona_last_sync';

    /**
     * Option pour la date de début de synchronisation
     */
    const OPTION_SYNC_START_DATE = 'edenpersona_sync_start_date';

    /**
     * Option pour les jours de dormance
     */
    const OPTION_DORMANCY_DAYS = 'edenpersona_dormancy_days';

    /**
     * Option pour la réduction du coupon de relance (%)
     */
    const OPTION_WINBACK_COUPON_DISCOUNT = 'edenpersona_winback_coupon_discount';

    /**
     * Option pour la validité du coupon de relance (jours)
     */
    const OPTION_WINBACK_COUPON_EXPIRY = 'edenpersona_winback_coupon_expiry';

    /**
     * Option pour le succès du test API
     */
    const OPTION_API_TEST_SUCCESS = 'edenpersona_api_test_success';

    /**
     * Option pour inclure les dimensions checkout dans le payload orders
     */
    const OPTION_INCLUDE_CHECKOUT_DIMENSIONS = 'edenpersona_include_checkout_dimensions';

    /**
     * Option pour inclure l'identité anonyme cross-session dans les payloads
     */
    const OPTION_INCLUDE_ANONYMOUS_IDENTITY = 'edenpersona_include_anonymous_identity';

    /**
     * Version du sel de hashage des emails (bumped à 2 après normalisation strtolower+trim)
     */
    const OPTION_SALT_VERSION = 'edenpersona_salt_version';

    /**
     * Version courante du sel (à bumper à chaque changement de la fonction hash_email)
     */
    const CURRENT_SALT_VERSION = 2;

    // ========================================
    // CONSTANTES API
    // ========================================

    /**
     * URL de l'API EdenPersona (Production)
     */
    const API_URL_PRODUCTION = 'https://www.edenpersona.com/en/connections/api-woocommerce-sync/';

    /**
     * URL de l'API EdenPersona (Development)
     */
    const API_URL_DEVELOPMENT = 'https://eden.local:8443/fr/connections/api-woocommerce-sync/';

    /**
     * URL de l'API EdenPersona (actuelle)
     */
    const API_URL = self::API_URL_PRODUCTION; // Changer pour DEVELOPMENT en développement

    // ========================================
    // CONSTANTES DE JOURNEY TRACKING
    // ========================================

    /**
     * Nom de la table des parcours clients
     */
    const JOURNEY_TABLE = 'edenpersona_customer_journeys';

    /**
     * Nom de la table de mapping hash → wp_user_id
     */
    const HASH_MAPPING_TABLE = 'edenpersona_hash_mapping';

    /**
     * Nom de la table customer ↔ persona (closed-loop)
     */
    const CUSTOMER_PERSONA_MAP_TABLE = 'edenpersona_customer_persona_map';

    /**
     * Option pour le secret webhook HMAC
     */
    const OPTION_WEBHOOK_SECRET = 'edenpersona_webhook_secret';

    /**
     * Option pour le workspace_id EdenPersona SaaS
     */
    const OPTION_WEBHOOK_WORKSPACE_ID = 'edenpersona_webhook_workspace_id';

    /**
     * Option : conserver les tags personas (taxonomie + user_meta) à la désinstallation.
     * Valeur par défaut : 1 (oui, conserver — pour ne pas surprendre).
     */
    const OPTION_PRESERVE_PERSONA_TAGS = 'edenpersona_preserve_persona_tags';

    /**
     * Option : activer le closed-loop (endpoint REST traite les syncs).
     * Conservée pour compatibilité legacy. Le closed-loop est désormais actif par défaut.
     */
    const OPTION_CLOSEDLOOP_ENABLED = 'edenpersona_closedloop_enabled';

    /**
     * Option : stats de la dernière sync reçue via l'endpoint.
     */
    const OPTION_LAST_CLOSEDLOOP_SYNC = 'edenpersona_last_closedloop_sync';

    /**
     * Clé de session pour le parcours
     */
    const JOURNEY_SESSION_KEY = 'edenpersona_journey';

    /**
     * Timeout de session du parcours (30 minutes en secondes)
     */
    const JOURNEY_SESSION_TIMEOUT = 1800;

    // ========================================
    // VALEURS PAR DÉFAUT
    // ========================================

    /**
     * Jours de dormance par défaut
     */
    const DEFAULT_DORMANCY_DAYS = 90;

    /**
     * Réduction par défaut pour les coupons de relance (%)
     */
    const DEFAULT_WINBACK_COUPON_DISCOUNT = 15;

    /**
     * Validité par défaut pour les coupons de relance (jours)
     */
    const DEFAULT_WINBACK_COUPON_EXPIRY = 7;

    /**
     * Période d'analyse par défaut (en jours)
     */
    const DEFAULT_ANALYSIS_PERIOD = 30;

    /**
     * Inclure les dimensions checkout dans le payload orders par défaut
     */
    const DEFAULT_INCLUDE_CHECKOUT_DIMENSIONS = true;

    /**
     * Inclure l'identité anonyme dans les payloads par défaut
     */
    const DEFAULT_INCLUDE_ANONYMOUS_IDENTITY = true;

    /**
     * Limite de mémoire requise (en MB)
     */
    const REQUIRED_MEMORY_LIMIT = 512;

    /**
     * Nombre maximum de pages pour la pagination
     */
    const MAX_PAGINATION_PAGES = 100;

    /**
     * Limite d'objets par page
     */
    const ITEMS_PER_PAGE = 50;

    // ========================================
    // MÉTHODES D'ACCÈS AUX OPTIONS
    // ========================================

    /**
     * Récupère le token API
     *
     * @return string Le token API ou chaîne vide
     */
    public static function get_api_token() {
        $encrypted_token = get_option( self::OPTION_TOKEN, '' );
        if ( empty( $encrypted_token ) ) {
            return '';
        }

        $token = EDENPERSONA_Utils::decrypt_token( $encrypted_token );

        // Auto-upgrade to secure format if currently using legacy or plain format
        if ( ! empty( $token ) && strpos( $encrypted_token, 'epv1:' ) !== 0 && strpos( $encrypted_token, 'eps1:' ) !== 0 ) {
            // Only upgrade if a secure encryption method is available
            if ( function_exists( 'openssl_encrypt' ) || function_exists( 'sodium_crypto_secretbox' ) ) {
                self::save_api_token( $token );
            }
        }

        return $token;
    }

    /**
     * Sauvegarde le token API
     *
     * @param string $token Le token API à sauvegarder
     * @return bool True si sauvegardé avec succès
     */
    public static function save_api_token( $token ) {
        $encrypted_token = EDENPERSONA_Utils::encrypt_token( $token );
        return update_option( self::OPTION_TOKEN, $encrypted_token );
    }

    /**
     * Récupère la date de dernière synchronisation
     *
     * @return string La date de dernière synchronisation ou chaîne vide
     */
    public static function get_last_sync() {
        return get_option( self::OPTION_LAST_SYNC, '' );
    }

    /**
     * Met à jour la date de dernière synchronisation
     *
     * @param string $date La date de synchronisation (optionnel, utilise la date actuelle si non fournie)
     * @return bool True si mis à jour avec succès
     */
    public static function update_last_sync( $date = null ) {
        $sync_date = $date ?: current_time( 'mysql' );
        return update_option( self::OPTION_LAST_SYNC, $sync_date );
    }

    /**
     * Récupère la date de début de synchronisation
     *
     * @return string La date de début de synchronisation ou chaîne vide
     */
    public static function get_sync_start_date() {
        return get_option( self::OPTION_SYNC_START_DATE, '' );
    }

    /**
     * Met à jour la date de début de synchronisation
     *
     * @param string $date La date de début de synchronisation
     * @return bool True si mis à jour avec succès
     */
    public static function update_sync_start_date( $date ) {
        return update_option( self::OPTION_SYNC_START_DATE, $date );
    }

    /**
     * Récupère les jours de dormance
     *
     * @return int Le nombre de jours de dormance
     */
    public static function get_dormancy_days() {
        return (int) get_option( self::OPTION_DORMANCY_DAYS, self::DEFAULT_DORMANCY_DAYS );
    }

    /**
     * Met à jour les jours de dormance
     *
     * @param int $days Le nombre de jours de dormance
     * @return bool True si mis à jour avec succès
     */
    public static function update_dormancy_days( $days ) {
        return update_option( self::OPTION_DORMANCY_DAYS, (int) $days );
    }

    /**
     * Récupère la réduction du coupon de relance (%)
     *
     * @return int La réduction en pourcentage
     */
    public static function get_winback_coupon_discount() {
        return (int) get_option( self::OPTION_WINBACK_COUPON_DISCOUNT, self::DEFAULT_WINBACK_COUPON_DISCOUNT );
    }

    /**
     * Récupère la validité du coupon de relance (jours)
     *
     * @return int Le nombre de jours de validité
     */
    public static function get_winback_coupon_expiry() {
        return (int) get_option( self::OPTION_WINBACK_COUPON_EXPIRY, self::DEFAULT_WINBACK_COUPON_EXPIRY );
    }

    /**
     * Récupère le statut du test API
     *
     * @return string La date du dernier test réussi ou chaîne vide
     */
    public static function get_api_test_success() {
        return get_option( self::OPTION_API_TEST_SUCCESS, '' );
    }

    /**
     * Met à jour le statut du test API
     *
     * @param string $date La date du test (optionnel, utilise la date actuelle si non fournie)
     * @return bool True si mis à jour avec succès
     */
    public static function update_api_test_success( $date = null ) {
        $test_date = $date ?: current_time( 'mysql' );
        return update_option( self::OPTION_API_TEST_SUCCESS, $test_date );
    }

    /**
     * Vérifie si les dimensions checkout doivent être incluses dans le payload orders.
     *
     * @return bool
     */
    public static function should_include_checkout_dimensions_in_payload() {
        $raw_value = get_option(
            self::OPTION_INCLUDE_CHECKOUT_DIMENSIONS,
            self::DEFAULT_INCLUDE_CHECKOUT_DIMENSIONS ? 1 : 0
        );

        return (bool) (int) $raw_value;
    }

    /**
     * Met à jour l'option d'inclusion des dimensions checkout.
     *
     * @param bool $enabled Activer/désactiver l'inclusion.
     * @return bool
     */
    public static function update_include_checkout_dimensions_in_payload( $enabled ) {
        return update_option( self::OPTION_INCLUDE_CHECKOUT_DIMENSIONS, $enabled ? 1 : 0 );
    }

    /**
     * Vérifie si l'identité anonyme doit être incluse dans les payloads.
     *
     * @return bool
     */
    public static function should_include_anonymous_identity_in_payload() {
        $raw_value = get_option(
            self::OPTION_INCLUDE_ANONYMOUS_IDENTITY,
            self::DEFAULT_INCLUDE_ANONYMOUS_IDENTITY ? 1 : 0
        );

        return (bool) (int) $raw_value;
    }

    /**
     * Met à jour l'option d'inclusion de l'identité anonyme dans les payloads.
     *
     * @param bool $enabled Activer/désactiver l'inclusion.
     * @return bool
     */
    public static function update_include_anonymous_identity_in_payload( $enabled ) {
        return update_option( self::OPTION_INCLUDE_ANONYMOUS_IDENTITY, $enabled ? 1 : 0 );
    }

    // ========================================
    // MÉTHODES DE VALIDATION
    // ========================================

    /**
     * Vérifie si le plugin est configuré
     *
     * @return bool True si le plugin est configuré
     */
    public static function is_configured() {
        return ! empty( self::get_api_token() );
    }

    /**
     * Vérifie si le test API a réussi récemment
     *
     * @param int $hours Le nombre d'heures pour considérer le test comme récent (défaut: 24)
     * @return bool True si le test API a réussi récemment
     */
    public static function is_api_test_recent( $hours = 24 ) {
        $last_test = self::get_api_test_success();
        if ( empty( $last_test ) ) {
            return false;
        }

        $test_time = strtotime( $last_test );
        $cutoff_time = strtotime( "-{$hours} hours" );
        
        return $test_time > $cutoff_time;
    }

    // ========================================
    // MÉTHODES DE NETTOYAGE
    // ========================================

    /**
     * Supprime toutes les options du plugin
     *
     * @return void
     */
    public static function delete_all_options() {
        delete_option( self::OPTION_TOKEN );
        delete_option( self::OPTION_LAST_SYNC );
        delete_option( self::OPTION_SYNC_START_DATE );
        delete_option( self::OPTION_DORMANCY_DAYS );
        delete_option( self::OPTION_API_TEST_SUCCESS );
        delete_option( self::OPTION_INCLUDE_CHECKOUT_DIMENSIONS );
        delete_option( self::OPTION_INCLUDE_ANONYMOUS_IDENTITY );
    }

    /**
     * Réinitialise les options de synchronisation
     *
     * @return void
     */
    public static function reset_sync_options() {
        delete_option( self::OPTION_LAST_SYNC );
        delete_option( self::OPTION_SYNC_START_DATE );
    }

    // ========================================
    // MÉTHODES UTILITAIRES
    // ========================================

    /**
     * Récupère l'URL de l'API selon l'environnement
     *
     * @param bool $force_production Forcer l'utilisation de l'URL de production
     * @return string L'URL de l'API
     */
    public static function get_api_url( $force_production = false ) {
        if ( defined( 'EDENPERSONA_API_URL' ) && ! empty( EDENPERSONA_API_URL ) ) {
            return esc_url_raw( EDENPERSONA_API_URL );
        }

        if ( $force_production ) {
            return self::API_URL_PRODUCTION;
        }

        // Local development stores should target local SaaS by default.
        $site_host = wp_parse_url( home_url(), PHP_URL_HOST );
        if ( self::is_local_environment_host( $site_host ) ) {
            return esc_url_raw( self::API_URL_DEVELOPMENT );
        }

        return esc_url_raw( self::API_URL );
    }

    /**
     * Determines if the current host belongs to a local dev environment.
     *
     * @param string|null $host Hostname to inspect.
     * @return bool
     */
    private static function is_local_environment_host( $host ) {
        if ( ! is_string( $host ) || '' === $host ) {
            return false;
        }

        $host = strtolower( trim( $host ) );
        if ( in_array( $host, array( 'localhost', '127.0.0.1', '::1' ), true ) ) {
            return true;
        }

        return (bool) preg_match( '/(\.local|\.localhost|\.test)$/', $host );
    }

    /**
     * Récupère la date de début d'analyse par défaut
     *
     * @param int $days Le nombre de jours à reculer (défaut: DEFAULT_ANALYSIS_PERIOD)
     * @return string La date au format Y-m-d
     */
    public static function get_default_start_date( $days = null ) {
        $period = $days ?: self::DEFAULT_ANALYSIS_PERIOD;
        return gmdate( 'Y-m-d', strtotime( "-{$period} days" ) );
    }

    /**
     * Récupère la date de fin d'analyse par défaut
     *
     * @return string La date actuelle au format Y-m-d
     */
    public static function get_default_end_date() {
        return gmdate( 'Y-m-d' );
    }

    /**
     * Vérifie si la limite de mémoire est suffisante
     *
     * @return bool True si la limite de mémoire est suffisante
     */
    public static function has_sufficient_memory() {
        $current_limit = ini_get( 'memory_limit' );
        if ( empty( $current_limit ) ) {
            return true; // Pas de limite définie, considérer comme OK
        }

        $current_bytes = wp_convert_hr_to_bytes( $current_limit );
        $required_bytes = self::REQUIRED_MEMORY_LIMIT * 1024 * 1024;

        return $current_bytes >= $required_bytes;
    }

    /**
     * Retourne la version courante du sel de hashage stockée en base.
     *
     * @return int
     */
    public static function get_salt_version() {
        return (int) get_option( self::OPTION_SALT_VERSION, 1 );
    }

    /**
     * Vérifie si le salt_version local est à jour.
     *
     * @return bool
     */
    public static function is_salt_version_current() {
        return self::get_salt_version() >= self::CURRENT_SALT_VERSION;
    }
}
