<?php
/**
 * Analytics and usage tracking system
 *
 * @link       https://mementor.no
 * @since      1.4.2
 * @package    TTSWP
 * @subpackage Mementor_TTS/includes
 */

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

class Mementor_TTS_Analytics {
    /**
     * Instance of the class
     */
    private static $instance = null;
    
    /**
     * Table name for analytics
     */
    private $table_name;
    
    /**
     * Table name for aggregated daily stats
     */
    private $daily_stats_table;
    
    /**
     * Data integrity helper
     */
    private $integrity_helper = null;
    
    /**
     * Get instance
     */
    public static function get_instance() {
        if (null === self::$instance) {
            self::$instance = new self();
        }
        return self::$instance;
    }
    
    /**
     * Constructor
     */
    private function __construct() {
        global $wpdb;
        $this->table_name = $wpdb->prefix . 'mementor_tts_analytics';
        $this->daily_stats_table = $wpdb->prefix . 'mementor_tts_daily_stats';
        
        // Initialize data integrity helper
        if (!class_exists('Mementor_TTS_Data_Integrity')) {
            require_once plugin_dir_path(__FILE__) . 'class-mementor-tts-data-integrity.php';
        }
        $this->integrity_helper = Mementor_TTS_Data_Integrity::get_instance();

        // Register the cron callback
        add_action('mementor_tts_aggregate_analytics', array($this, 'aggregate_daily_stats'));

        // Only check scheduling on admin requests
        if (is_admin()) {
            add_action('admin_init', function () {
                if (!wp_next_scheduled('mementor_tts_aggregate_analytics')) {
                    wp_schedule_event(strtotime('tomorrow 2am'), 'daily', 'mementor_tts_aggregate_analytics');
                }
            });
        }
    }
    
    /**
     * Create analytics tables
     */
    public function create_tables() {
        global $wpdb;
        
        $charset_collate = $wpdb->get_charset_collate();
        
        // Main analytics table - stores individual events
        $sql1 = "CREATE TABLE IF NOT EXISTS {$this->table_name} (
            id bigint(20) NOT NULL AUTO_INCREMENT,
            event_type varchar(50) NOT NULL,
            user_type varchar(20) NOT NULL DEFAULT 'free',
            domain_hash varchar(64) NOT NULL,
            credits_used int(11) NOT NULL DEFAULT 0,
            plugin_version varchar(20) NOT NULL,
            pro_version varchar(20) DEFAULT NULL,
            voice_id varchar(100) DEFAULT NULL,
            model_id varchar(50) DEFAULT NULL,
            text_length int(11) DEFAULT NULL,
            language_code varchar(10) DEFAULT NULL,
            api_type varchar(20) DEFAULT 'user',
            error_code varchar(50) DEFAULT NULL,
            processing_time float DEFAULT NULL,
            user_agent_hash varchar(64) DEFAULT NULL,
            country_code varchar(2) DEFAULT NULL,
            created_at datetime DEFAULT CURRENT_TIMESTAMP,
            PRIMARY KEY (id),
            KEY idx_event_type (event_type),
            KEY idx_domain_hash (domain_hash),
            KEY idx_created_at (created_at),
            KEY idx_user_type (user_type),
            KEY idx_api_type (api_type)
        ) $charset_collate;";
        
        // Daily aggregated stats table
        $sql2 = "CREATE TABLE IF NOT EXISTS {$this->daily_stats_table} (
            id bigint(20) NOT NULL AUTO_INCREMENT,
            date date NOT NULL,
            domain_hash varchar(64) NOT NULL,
            user_type varchar(20) NOT NULL,
            total_requests int(11) NOT NULL DEFAULT 0,
            total_credits int(11) NOT NULL DEFAULT 0,
            unique_voices int(11) NOT NULL DEFAULT 0,
            error_count int(11) NOT NULL DEFAULT 0,
            avg_text_length float DEFAULT NULL,
            plugin_version varchar(20) NOT NULL,
            suspicious_score int(11) NOT NULL DEFAULT 0,
            data_hash varchar(64) NOT NULL,
            created_at datetime DEFAULT CURRENT_TIMESTAMP,
            PRIMARY KEY (id),
            UNIQUE KEY idx_date_domain (date, domain_hash),
            KEY idx_suspicious_score (suspicious_score)
        ) $charset_collate;";
        
        require_once(ABSPATH . 'wp-admin/includes/upgrade.php');
        dbDelta($sql1);
        dbDelta($sql2);
        
        // Store version for future updates
        update_option('mementor_tts_analytics_db_version', '1.0', false);
    }
    
    /**
     * Log an analytics event
     * 
     * @param string $event_type Type of event (e.g., 'text_to_speech', 'api_test', 'error')
     * @param array $data Event data
     */
    public function log_event($event_type, $data = array()) {
        global $wpdb;
        
        // Check if analytics is enabled
        if (!$this->is_analytics_enabled()) {
            return;
        }
        
        // Prepare event data
        $event_data = $this->prepare_event_data($event_type, $data);
        
        // Insert into database
        $wpdb->insert(
            $this->table_name,
            $event_data,
            array(
                '%s', '%s', '%s', '%d', '%s', '%s', '%s', '%s', '%d', 
                '%s', '%s', '%s', '%f', '%s', '%s', '%s'
            )
        );
        
        // Check for suspicious patterns immediately
        $this->check_suspicious_activity($event_data['domain_hash']);
    }
    
    /**
     * Prepare event data for logging
     * 
     * @param string $event_type Event type
     * @param array $data Raw event data
     * @return array Prepared data
     */
    private function prepare_event_data($event_type, $data) {
        $domain_info = $this->get_domain_info();
        
        $event_data = array(
            'event_type' => sanitize_text_field($event_type),
            'user_type' => $this->get_user_type(),
            'domain_hash' => $domain_info['hash'],
            'credits_used' => isset($data['credits_used']) ? absint($data['credits_used']) : 0,
            'plugin_version' => MEMENTOR_TTS_VERSION,
            'pro_version' => null, // PRO plugin discontinued
            'voice_id' => isset($data['voice_id']) ? sanitize_text_field($data['voice_id']) : null,
            'model_id' => isset($data['model_id']) ? sanitize_text_field($data['model_id']) : null,
            'text_length' => isset($data['text_length']) ? absint($data['text_length']) : null,
            'language_code' => isset($data['language_code']) ? sanitize_text_field($data['language_code']) : null,
            'api_type' => $this->determine_api_type($data),
            'error_code' => isset($data['error_code']) ? sanitize_text_field($data['error_code']) : null,
            'processing_time' => isset($data['processing_time']) ? floatval($data['processing_time']) : null,
            'user_agent_hash' => $this->get_user_agent_hash(),
            'country_code' => $domain_info['country'],
            'created_at' => current_time('mysql')
        );
        
        return $event_data;
    }
    
    /**
     * Get domain information
     * 
     * @return array Domain hash and country
     */
    private function get_domain_info() {
        $domain = parse_url(site_url(), PHP_URL_HOST);
        
        // Remove www. prefix for consistency
        $domain = preg_replace('/^www\./', '', $domain);
        
        // Create hash for privacy
        $hash = hash('sha256', $domain . '|' . get_option('admin_email'));
        
        // Try to determine country from domain TLD
        $country = $this->guess_country_from_domain($domain);
        
        return array(
            'hash' => $hash,
            'country' => $country,
            'domain' => $domain // Not stored, just for internal use
        );
    }
    
    /**
     * Guess country from domain TLD
     * 
     * @param string $domain Domain name
     * @return string|null Country code
     */
    private function guess_country_from_domain($domain) {
        // Common country TLDs
        $tld_map = array(
            '.uk' => 'GB', '.co.uk' => 'GB',
            '.de' => 'DE', '.fr' => 'FR',
            '.es' => 'ES', '.it' => 'IT',
            '.nl' => 'NL', '.be' => 'BE',
            '.ch' => 'CH', '.at' => 'AT',
            '.dk' => 'DK', '.se' => 'SE',
            '.no' => 'NO', '.fi' => 'FI',
            '.pl' => 'PL', '.cz' => 'CZ',
            '.ru' => 'RU', '.jp' => 'JP',
            '.cn' => 'CN', '.in' => 'IN',
            '.au' => 'AU', '.nz' => 'NZ',
            '.ca' => 'CA', '.br' => 'BR',
            '.mx' => 'MX', '.za' => 'ZA'
        );
        
        foreach ($tld_map as $tld => $country) {
            if (substr($domain, -strlen($tld)) === $tld) {
                return $country;
            }
        }
        
        // Default to US for .com, .org, .net
        if (preg_match('/\.(com|org|net|io)$/', $domain)) {
            return 'US';
        }
        
        return null;
    }
    
    /**
     * Get user type (free/pro)
     * 
     * @return string
     */
    private function get_user_type() {
        return ttswp_has_paid_plan() ? 'pro' : 'free';
    }
    
    /**
     * Determine API type (user/shared/pro)
     * 
     * @param array $data Event data
     * @return string
     */
    private function determine_api_type($data) {
        if (isset($data['api_type'])) {
            return $data['api_type'];
        }
        
        if (isset($data['using_shared_key']) && $data['using_shared_key']) {
            return 'shared';
        }
        
        if (isset($data['using_pro_key']) && $data['using_pro_key']) {
            return 'pro';
        }
        
        return 'user';
    }
    
    /**
     * Get user agent hash
     * 
     * @return string
     */
    private function get_user_agent_hash() {
        $user_agent = isset($_SERVER['HTTP_USER_AGENT']) ? sanitize_text_field(wp_unslash($_SERVER['HTTP_USER_AGENT'])) : 'unknown';
        return substr(hash('sha256', $user_agent), 0, 16);
    }
    
    /**
     * Check for suspicious activity
     * 
     * @param string $domain_hash Domain hash to check
     */
    private function check_suspicious_activity($domain_hash) {
        global $wpdb;
        
        // Get activity from last hour
        $one_hour_ago = date('Y-m-d H:i:s', strtotime('-1 hour'));
        
        $stats = $wpdb->get_row($wpdb->prepare(
            "SELECT 
                COUNT(*) as request_count,
                SUM(credits_used) as total_credits,
                COUNT(DISTINCT voice_id) as unique_voices,
                COUNT(DISTINCT user_agent_hash) as unique_agents,
                MIN(created_at) as first_request,
                MAX(created_at) as last_request
             FROM {$this->table_name}
             WHERE domain_hash = %s AND created_at > %s",
            $domain_hash, $one_hour_ago
        ));
        
        if (!$stats) {
            return;
        }
        
        $suspicious_score = 0;
        
        // High request rate (>100 per hour)
        if ($stats->request_count > 100) {
            $suspicious_score += 20;
        }
        
        // Very high credit usage (>10000 per hour)
        if ($stats->total_credits > 10000) {
            $suspicious_score += 30;
        }
        
        // Using many different voices (>20)
        if ($stats->unique_voices > 20) {
            $suspicious_score += 15;
        }
        
        // Many different user agents (possible bot)
        if ($stats->unique_agents > 10) {
            $suspicious_score += 25;
        }
        
        // Check request patterns
        if ($stats->request_count > 10) {
            $duration = strtotime($stats->last_request) - strtotime($stats->first_request);
            if ($duration > 0) {
                $avg_interval = $duration / $stats->request_count;
                // Very regular intervals (automated)
                if ($avg_interval < 5) { // Less than 5 seconds between requests
                    $suspicious_score += 20;
                }
            }
        }
        
        // Log suspicious activity
        if ($suspicious_score >= 50) {
            $this->log_suspicious_domain($domain_hash, $suspicious_score, $stats);
        }
    }
    
    /**
     * Log suspicious domain
     * 
     * @param string $domain_hash Domain hash
     * @param int $score Suspicious score
     * @param object $stats Activity stats
     */
    private function log_suspicious_domain($domain_hash, $score, $stats) {
        $suspicious_data = array(
            'domain_hash' => $domain_hash,
            'score' => $score,
            'stats' => $stats,
            'timestamp' => current_time('mysql')
        );
        
        // Store in transient for admin review
        $suspicious_domains = get_transient('mementor_tts_suspicious_domains') ?: array();
        $suspicious_domains[$domain_hash] = $suspicious_data;
        
        // Keep only last 100 entries
        if (count($suspicious_domains) > 100) {
            $suspicious_domains = array_slice($suspicious_domains, -100, 100, true);
        }
        
        set_transient('mementor_tts_suspicious_domains', $suspicious_domains, WEEK_IN_SECONDS);
        
        // Log to error log if debug is enabled
        if (mementor_tts_is_debug_enabled()) {
            error_log(sprintf(
                'Mementor TTS: Suspicious activity detected - Domain: %s, Score: %d, Requests: %d, Credits: %d',
                substr($domain_hash, 0, 8) . '...',
                $score,
                $stats->request_count,
                $stats->total_credits
            ));
        }
    }
    
    /**
     * Get analytics summary for admin
     * 
     * @param string $period Period to analyze (today, week, month)
     * @return array
     */
    public function get_analytics_summary($period = 'week') {
        global $wpdb;
        
        $date_condition = $this->get_date_condition($period);
        
        // Overall stats
        $overall = $wpdb->get_row(
            "SELECT 
                COUNT(*) as total_requests,
                COUNT(DISTINCT domain_hash) as unique_domains,
                SUM(credits_used) as total_credits,
                AVG(text_length) as avg_text_length,
                COUNT(CASE WHEN error_code IS NOT NULL THEN 1 END) as error_count
             FROM {$this->table_name}
             WHERE {$date_condition}"
        );
        
        // By user type
        $by_user_type = $wpdb->get_results(
            "SELECT 
                user_type,
                COUNT(*) as request_count,
                SUM(credits_used) as credits_used
             FROM {$this->table_name}
             WHERE {$date_condition}
             GROUP BY user_type"
        );
        
        // By API type
        $by_api_type = $wpdb->get_results(
            "SELECT 
                api_type,
                COUNT(*) as request_count,
                SUM(credits_used) as credits_used
             FROM {$this->table_name}
             WHERE {$date_condition}
             GROUP BY api_type"
        );
        
        // Top voices
        $top_voices = $wpdb->get_results(
            "SELECT 
                voice_id,
                COUNT(*) as usage_count
             FROM {$this->table_name}
             WHERE {$date_condition} AND voice_id IS NOT NULL
             GROUP BY voice_id
             ORDER BY usage_count DESC
             LIMIT 10"
        );
        
        // Suspicious domains
        $suspicious_domains = get_transient('mementor_tts_suspicious_domains') ?: array();
        
        return array(
            'overall' => $overall,
            'by_user_type' => $by_user_type,
            'by_api_type' => $by_api_type,
            'top_voices' => $top_voices,
            'suspicious_count' => count($suspicious_domains)
        );
    }
    
    /**
     * Get date condition for queries
     * 
     * @param string $period Period name
     * @return string SQL condition
     */
    private function get_date_condition($period) {
        global $wpdb;
        switch ($period) {
            case 'today':
                return $wpdb->prepare("DATE(created_at) = %s", current_time('Y-m-d'));
            case 'week':
                return $wpdb->prepare("created_at >= %s", gmdate('Y-m-d H:i:s', strtotime('-7 days')));
            case 'month':
                return $wpdb->prepare("created_at >= %s", gmdate('Y-m-d H:i:s', strtotime('-30 days')));
            case 'year':
                return $wpdb->prepare("created_at >= %s", gmdate('Y-m-d H:i:s', strtotime('-1 year')));
            default:
                return "1=1";
        }
    }
    
    /**
     * Aggregate daily stats
     * This runs via cron to create summary data
     */
    public function aggregate_daily_stats() {
        global $wpdb;
        
        // Get yesterday's date
        $yesterday = date('Y-m-d', strtotime('-1 day'));
        
        // Check if already aggregated
        $exists = $wpdb->get_var($wpdb->prepare(
            "SELECT COUNT(*) FROM {$this->daily_stats_table} WHERE date = %s",
            $yesterday
        ));
        
        if ($exists > 0) {
            return; // Already aggregated
        }
        
        // Aggregate by domain
        $domains = $wpdb->get_results($wpdb->prepare(
            "SELECT 
                domain_hash,
                user_type,
                COUNT(*) as total_requests,
                SUM(credits_used) as total_credits,
                COUNT(DISTINCT voice_id) as unique_voices,
                COUNT(CASE WHEN error_code IS NOT NULL THEN 1 END) as error_count,
                AVG(text_length) as avg_text_length,
                MAX(plugin_version) as plugin_version
             FROM {$this->table_name}
             WHERE DATE(created_at) = %s
             GROUP BY domain_hash, user_type",
            $yesterday
        ));
        
        foreach ($domains as $domain_data) {
            // Calculate suspicious score based on daily activity
            $suspicious_score = $this->calculate_daily_suspicious_score($domain_data);
            
            // Create data hash for integrity
            $data_string = implode('|', array(
                $yesterday,
                $domain_data->domain_hash,
                $domain_data->total_requests,
                $domain_data->total_credits
            ));
            $data_hash = $this->integrity_helper->generate_signature(
                array('data' => $data_string),
                'daily_stats'
            );
            
            // Insert aggregated data
            $wpdb->insert(
                $this->daily_stats_table,
                array(
                    'date' => $yesterday,
                    'domain_hash' => $domain_data->domain_hash,
                    'user_type' => $domain_data->user_type,
                    'total_requests' => $domain_data->total_requests,
                    'total_credits' => $domain_data->total_credits,
                    'unique_voices' => $domain_data->unique_voices,
                    'error_count' => $domain_data->error_count,
                    'avg_text_length' => $domain_data->avg_text_length,
                    'plugin_version' => $domain_data->plugin_version,
                    'suspicious_score' => $suspicious_score,
                    'data_hash' => $data_hash
                ),
                array('%s', '%s', '%s', '%d', '%d', '%d', '%d', '%f', '%s', '%d', '%s')
            );
        }
        
        // Clean up old raw data (keep 30 days)
        $this->cleanup_old_data();
    }
    
    /**
     * Calculate daily suspicious score
     * 
     * @param object $data Domain data
     * @return int
     */
    private function calculate_daily_suspicious_score($data) {
        $score = 0;
        
        // High daily requests (>1000)
        if ($data->total_requests > 1000) {
            $score += 20;
        }
        
        // Very high daily credits (>50000)
        if ($data->total_credits > 50000) {
            $score += 30;
        }
        
        // High error rate (>20%)
        if ($data->total_requests > 0) {
            $error_rate = ($data->error_count / $data->total_requests) * 100;
            if ($error_rate > 20) {
                $score += 25;
            }
        }
        
        // Using many voices (>30 per day)
        if ($data->unique_voices > 30) {
            $score += 15;
        }
        
        return $score;
    }
    
    /**
     * Clean up old analytics data
     */
    private function cleanup_old_data() {
        global $wpdb;
        
        // Keep raw data for 30 days
        $cutoff_date = date('Y-m-d H:i:s', strtotime('-30 days'));
        
        $wpdb->query($wpdb->prepare(
            "DELETE FROM {$this->table_name} WHERE created_at < %s",
            $cutoff_date
        ));
        
        // Keep daily stats for 1 year
        $yearly_cutoff = date('Y-m-d', strtotime('-1 year'));
        
        $wpdb->query($wpdb->prepare(
            "DELETE FROM {$this->daily_stats_table} WHERE date < %s",
            $yearly_cutoff
        ));
    }
    
    // Scheduling moved to constructor + admin_init hook
    
    /**
     * Check if analytics is enabled
     * 
     * @return bool
     */
    private function is_analytics_enabled() {
        // Check if disabled via constant
        if (defined('MEMENTOR_TTS_DISABLE_ANALYTICS') && MEMENTOR_TTS_DISABLE_ANALYTICS) {
            return false;
        }
        
        // Check option
        return get_option('mementor_tts_enable_analytics', true);
    }
    
}