<?php
/**
 * Handle user credit tracking for free tier
 *
 * @link       https://mementor.no
 * @since      1.3.0
 * @package    TTSWP
 * @subpackage Mementor_TTS/includes
 */

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

class Mementor_TTS_User_Credits {
    /**
     * Instance of the class
     */
    private static $instance = null;
    
    /**
     * Table name for user credits
     */
    private $table_name;
    
    /**
     * Data integrity helper
     */
    private $integrity_helper = null;
    
    /**
     * Maximum free credits per user
     */
    const FREE_CREDITS_LIMIT = 10000;
    
    /**
     * Constructor
     */
    private function __construct() {
        global $wpdb;
        $this->table_name = $wpdb->prefix . 'mementor_tts_user_credits';
        
        // 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();
    }
    
    /**
     * Get instance of the class
     */
    public static function get_instance() {
        if (null === self::$instance) {
            self::$instance = new self();
        }
        return self::$instance;
    }
    
    /**
     * Create the user credits table
     */
    public function create_table() {
        global $wpdb;
        
        $charset_collate = $wpdb->get_charset_collate();
        
        $sql = "CREATE TABLE IF NOT EXISTS {$this->table_name} (
            id bigint(20) NOT NULL AUTO_INCREMENT,
            user_id bigint(20) NOT NULL,
            email_hash varchar(64) DEFAULT NULL,
            credits_used int(11) NOT NULL DEFAULT 0,
            first_generation_date datetime DEFAULT NULL,
            last_generation_date datetime DEFAULT NULL,
            reset_count int(11) NOT NULL DEFAULT 0,
            user_fingerprint varchar(255) DEFAULT NULL,
            site_identifier varchar(255) DEFAULT NULL,
            integrity_hash varchar(64) DEFAULT NULL,
            created_at datetime DEFAULT CURRENT_TIMESTAMP,
            updated_at datetime DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
            PRIMARY KEY (id),
            UNIQUE KEY user_id (user_id),
            KEY email_hash (email_hash),
            KEY user_fingerprint (user_fingerprint),
            KEY site_identifier (site_identifier)
        ) $charset_collate;";
        
        require_once(ABSPATH . 'wp-admin/includes/upgrade.php');
        dbDelta($sql);
        
        // Store version for future updates
        update_option('mementor_tts_user_credits_db_version', '1.1', false);
    }
    
    /**
     * Get user fingerprint
     * Creates a unique identifier that persists across sessions
     */
    private function get_user_fingerprint($user_id = null) {
        $fingerprint_parts = array();
        
        // User-specific data
        if ($user_id) {
            $user = get_user_by('id', $user_id);
            if ($user) {
                $fingerprint_parts[] = $user->user_email;
                $fingerprint_parts[] = $user->user_registered;
            }
        }
        
        // Site-specific data
        $fingerprint_parts[] = get_site_url();
        $fingerprint_parts[] = get_option('admin_email');
        $fingerprint_parts[] = DB_NAME;
        
        // Server-specific data (careful not to be too specific)
        if (isset($_SERVER['SERVER_NAME'])) {
            $fingerprint_parts[] = sanitize_text_field($_SERVER['SERVER_NAME']);
        }
        
        // Create hash
        return hash('sha256', implode('|', $fingerprint_parts));
    }
    
    /**
     * Get site identifier
     * Used to track the same installation even after deactivation/reactivation
     */
    private function get_site_identifier() {
        $site_parts = array(
            get_site_url(),
            get_option('admin_email'),
            DB_NAME,
            defined('DB_HOST') ? DB_HOST : '',
            get_option('WPLANG', 'en_US')
        );
        
        return hash('sha256', implode('|', $site_parts));
    }
    
    /**
     * Generate integrity hash for credit data
     * This prevents tampering with database values
     */
    private function generate_integrity_hash($user_id, $credits_used, $timestamp) {
        if ($this->integrity_helper) {
            return $this->integrity_helper->sign_credit_data($user_id, $credits_used, $timestamp);
        }
        
        // Fallback to old method if integrity helper not available
        $secret_key = get_option('mementor_tts_integrity_secret');
        
        if (!$secret_key) {
            $secret_key = wp_generate_password(64, true, true);
            update_option('mementor_tts_integrity_secret', $secret_key, false);
        }
        
        $data = array(
            $user_id,
            $credits_used,
            $timestamp,
            $this->get_site_identifier(),
            $secret_key
        );
        
        return hash_hmac('sha256', implode('|', $data), $secret_key);
    }
    
    /**
     * Verify integrity of credit data
     */
    private function verify_integrity($credits_data) {
        if (!$credits_data) {
            return false;
        }
        
        // Bypass for admin user during development
        if ($credits_data->user_id == 1 && current_user_can('manage_options')) {
            return true;
        }
        
        // If no integrity hash exists (old record or new record), consider it valid
        // The migration will add hashes to old records
        if (!isset($credits_data->integrity_hash) || empty($credits_data->integrity_hash)) {
            return true;
        }
        
        // Use new integrity helper if available
        if ($this->integrity_helper) {
            return $this->integrity_helper->verify_credit_signature(
                $credits_data->user_id,
                $credits_data->credits_used,
                $credits_data->last_generation_date ?: $credits_data->created_at,
                $credits_data->integrity_hash
            );
        }
        
        // Fallback to old method
        $expected_hash = $this->generate_integrity_hash(
            $credits_data->user_id,
            $credits_data->credits_used,
            $credits_data->last_generation_date ?: $credits_data->created_at
        );
        
        return hash_equals($expected_hash, $credits_data->integrity_hash);
    }
    
    /**
     * Get user credit data
     */
    public function get_user_credits($user_id = null) {
        global $wpdb;
        
        if (!$user_id) {
            $user_id = get_current_user_id();
        }
        
        if (!$user_id) {
            return null;
        }
        
        $user = get_user_by('id', $user_id);
        $email_hash = $user ? hash('sha256', strtolower($user->user_email)) : null;
        $fingerprint = $this->get_user_fingerprint($user_id);
        $site_identifier = $this->get_site_identifier();

        // For site-wide credit sharing, find the single record for this installation
        // Credits are shared across all users on the same site (prevent admin abuse)
        // The site_identifier ensures all users on this install share the same credit pool
        $sql = $wpdb->prepare(
            "SELECT * FROM {$this->table_name}
             WHERE site_identifier = %s
             LIMIT 1",
            $site_identifier
        );

        $result = $wpdb->get_row($sql);
        
        // If no record exists, create one
        if (!$result) {
            $this->initialize_user_credits($user_id);
            // Try to get the record again, but don't recurse
            $result = $wpdb->get_row($sql);
            if (!$result) {
                // Failed to create record, return null to prevent infinite loop
                if (mementor_tts_is_debug_enabled()) {
                    error_log('TTS Plugin: Failed to create user credits record for user ' . $user_id);
                }
                return null;
            }
        }
        
        // Verify integrity of the data
        // For site-wide shared credits, integrity hash is based on the original user_id
        // who created the record. Skip integrity check if current user differs (shared access).
        $is_original_user = ($result->user_id == $user_id);

        if ($is_original_user && !$this->verify_integrity($result)) {
            // Data has been tampered with by the original user
            // Check backup storage
            $backup_key = 'mementor_tts_credits_' . $this->get_site_identifier();
            $backup_data = get_option($backup_key, array());

            // Check if ANY user on this site has exhausted credits according to backup
            $max_credits_used = 0;
            foreach ($backup_data as $uid => $data) {
                if (isset($data['credits_used']) && $data['credits_used'] > $max_credits_used) {
                    $max_credits_used = $data['credits_used'];
                }
            }

            if ($max_credits_used >= self::FREE_CREDITS_LIMIT) {
                // Site has exhausted credits according to backup
                // Update database to match backup
                $wpdb->update(
                    $this->table_name,
                    array(
                        'credits_used' => self::FREE_CREDITS_LIMIT,
                        'integrity_hash' => $this->generate_integrity_hash(
                            $result->user_id,
                            self::FREE_CREDITS_LIMIT,
                            $result->last_generation_date ?: current_time('mysql')
                        )
                    ),
                    array('id' => $result->id)
                );
                $result->credits_used = self::FREE_CREDITS_LIMIT;
            } else {
                // Log tampering attempt
                if (mementor_tts_is_debug_enabled()) {
                    error_log('TTS Plugin: Credit data tampering detected for site (user ' . $user_id . ')');
                }

                // Reset to maximum credits as a penalty
                $wpdb->update(
                    $this->table_name,
                    array(
                        'credits_used' => self::FREE_CREDITS_LIMIT,
                        'reset_count' => $result->reset_count + 1,
                        'integrity_hash' => $this->generate_integrity_hash(
                            $result->user_id,
                            self::FREE_CREDITS_LIMIT,
                            current_time('mysql')
                        )
                    ),
                    array('id' => $result->id)
                );
                $result->credits_used = self::FREE_CREDITS_LIMIT;
            }
        }

        // Note: user_id is NOT updated for site-wide shared credits
        // The user_id field indicates who first created the shared credit pool
        // All users on this site access the same record via site_identifier

        return $result;
    }
    
    /**
     * Initialize user credits record
     */
    private function initialize_user_credits($user_id) {
        global $wpdb;
        
        $user = get_user_by('id', $user_id);
        $email_hash = $user ? hash('sha256', strtolower($user->user_email)) : null;
        $created_time = current_time('mysql');
        
        $wpdb->insert(
            $this->table_name,
            array(
                'user_id' => $user_id,
                'email_hash' => $email_hash,
                'credits_used' => 0,
                'user_fingerprint' => $this->get_user_fingerprint($user_id),
                'site_identifier' => $this->get_site_identifier(),
                'integrity_hash' => $this->generate_integrity_hash($user_id, 0, $created_time),
                'created_at' => $created_time,
                'updated_at' => $created_time
            ),
            array('%d', '%s', '%d', '%s', '%s', '%s', '%s', '%s')
        );
    }
    
    /**
     * Check if user has credits remaining
     */
    public function has_credits_remaining($user_id = null) {
        // Block WordPress playground domains
        if ($this->is_wordpress_playground()) {
            return false;
        }

        // Paid plan users use SaaS credits, not free credits — bypass this check
        if (ttswp_has_paid_plan()) {
            return true;
        }

        $credits_data = $this->get_user_credits($user_id);

        if (!$credits_data) {
            return true; // Allow if we can't track
        }

        return $credits_data->credits_used < self::FREE_CREDITS_LIMIT;
    }
    
    /**
     * Get remaining credits
     */
    public function get_remaining_credits($user_id = null) {
        $credits_data = $this->get_user_credits($user_id);
        
        if (!$credits_data) {
            return self::FREE_CREDITS_LIMIT;
        }
        $remaining = self::FREE_CREDITS_LIMIT - $credits_data->credits_used;
        return max(0, $remaining);
    }
    
    /**
     * Use credits
     * 
     * @param int $amount Amount of credits to use
     * @param int $user_id User ID
     * @return bool True if credits were used successfully
     */
    public function use_credits($amount, $user_id = null) {
        global $wpdb;
        
        if (!$user_id) {
            $user_id = get_current_user_id();
        }
        
        $credits_data = $this->get_user_credits($user_id);
        
        if (!$credits_data) {
            return false;
        }
        
        // Check if user has enough credits
        $new_total = $credits_data->credits_used + $amount;
        if ($new_total > self::FREE_CREDITS_LIMIT) {
            return false;
        }
        
        $current_time = current_time('mysql');
        
        // Update credits with new integrity hash
        $updated = $wpdb->update(
            $this->table_name,
            array(
                'credits_used' => $new_total,
                'last_generation_date' => $current_time,
                'first_generation_date' => $credits_data->first_generation_date ?: $current_time,
                'integrity_hash' => $this->generate_integrity_hash($user_id, $new_total, $current_time)
            ),
            array('id' => $credits_data->id),
            array('%d', '%s', '%s', '%s'),
            array('%d')
        );
        
        // Also update in WordPress options as backup
        $this->update_backup_storage($user_id, $new_total);
        
        // Log credit usage for monitoring
        if ($updated !== false && mementor_tts_is_debug_enabled()) {
            error_log(sprintf(
                'TTS Plugin: User %d used %d credits. Total: %d/%d',
                $user_id,
                $amount,
                $new_total,
                self::FREE_CREDITS_LIMIT
            ));
        }
        
        return $updated !== false;
    }
    
    /**
     * Update backup storage in WordPress options
     * This survives plugin deactivation
     */
    private function update_backup_storage($user_id, $credits_used) {
        $backup_key = 'mementor_tts_credits_' . $this->get_site_identifier();
        $backup_data = get_option($backup_key, array());
        
        if (!is_array($backup_data)) {
            $backup_data = array();
        }
        
        $backup_data[$user_id] = array(
            'credits_used' => $credits_used,
            'last_update' => current_time('mysql'),
            'fingerprint' => $this->get_user_fingerprint($user_id)
        );
        
        update_option($backup_key, $backup_data, false);
    }
    
    /**
     * Check for reset attempts
     *
     * For site-wide shared credits, checks if this site has exhausted credits
     * and someone is trying to reset by creating new users or reinstalling.
     *
     * @return bool True if this appears to be a reset attempt
     */
    public function detect_reset_attempt($user_id = null) {
        global $wpdb;

        if (!$user_id) {
            $user_id = get_current_user_id();
        }

        // Check backup storage for site-wide credit exhaustion
        $backup_key = 'mementor_tts_credits_' . $this->get_site_identifier();
        $backup_data = get_option($backup_key, array());

        // For site-wide credits, check if ANY user on this site exhausted credits
        foreach ($backup_data as $uid => $data) {
            if (isset($data['credits_used']) && $data['credits_used'] >= self::FREE_CREDITS_LIMIT) {
                // This site has previously exhausted credits
                return true;
            }
        }

        // Check for site_identifier match with exhausted credits
        $site_identifier = $this->get_site_identifier();
        $existing = $wpdb->get_var($wpdb->prepare(
            "SELECT COUNT(*) FROM {$this->table_name}
             WHERE site_identifier = %s
             AND credits_used >= %d",
            $site_identifier,
            self::FREE_CREDITS_LIMIT
        ));

        if ($existing > 0) {
            return true;
        }

        // Check for fingerprint match (additional abuse prevention)
        $fingerprint = $this->get_user_fingerprint($user_id);
        $existing = $wpdb->get_var($wpdb->prepare(
            "SELECT COUNT(*) FROM {$this->table_name}
             WHERE user_fingerprint = %s
             AND credits_used >= %d",
            $fingerprint,
            self::FREE_CREDITS_LIMIT
        ));

        return $existing > 0;
    }
    
    /**
     * Get credit usage statistics
     */
    public function get_usage_stats($user_id = null) {
        $credits_data = $this->get_user_credits($user_id);
        
        if (!$credits_data) {
            return array(
                'used' => 0,
                'remaining' => self::FREE_CREDITS_LIMIT,
                'total' => self::FREE_CREDITS_LIMIT,
                'percentage' => 0,
                'first_use' => null,
                'last_use' => null
            );
        }
        
        $used = $credits_data->credits_used;
        $remaining = self::FREE_CREDITS_LIMIT - $used;
        $percentage = round(($used / self::FREE_CREDITS_LIMIT) * 100);
        
        return array(
            'used' => $used,
            'remaining' => max(0, $remaining),
            'total' => self::FREE_CREDITS_LIMIT,
            'percentage' => min(100, $percentage),
            'first_use' => $credits_data->first_generation_date,
            'last_use' => $credits_data->last_generation_date
        );
    }
    
    /**
     * Reset site-wide credits - admin function
     *
     * Since credits are shared across all users on a site, this resets
     * the entire site's credit pool, not just for one user.
     */
    public function reset_user_credits($user_id = null) {
        global $wpdb;

        if (!$user_id) {
            $user_id = get_current_user_id();
        }

        if (!$user_id || !current_user_can('manage_options')) {
            return false;
        }

        // Set bypass flag for 60 seconds
        set_transient('mementor_tts_bypass_integrity_check_' . $user_id, true, 60);

        // For site-wide credits, delete the site's credit record
        $site_identifier = $this->get_site_identifier();

        $wpdb->query($wpdb->prepare(
            "DELETE FROM {$this->table_name}
             WHERE site_identifier = %s",
            $site_identifier
        ));

        // Clear ALL backup data for this site
        $backup_key = 'mementor_tts_credits_' . $this->get_site_identifier();
        delete_option($backup_key);

        // Clear any cached data
        wp_cache_delete('mementor_tts_user_credits_' . $user_id, 'options');

        // Create a fresh record with 0 credits while bypass is active
        $user = get_user_by('id', $user_id);
        $email_hash = $user ? hash('sha256', strtolower($user->user_email)) : null;

        $wpdb->insert(
            $this->table_name,
            array(
                'user_id' => $user_id,
                'email_hash' => $email_hash,
                'credits_used' => 0,
                'user_fingerprint' => $this->get_user_fingerprint($user_id),
                'site_identifier' => $site_identifier,
                'integrity_hash' => $this->generate_integrity_hash($user_id, 0, current_time('mysql'))
            )
        );

        return true;
    }
    
    /**
     * Migrate existing records to include integrity hashes
     * This runs on plugin update
     */
    public function migrate_integrity_hashes() {
        global $wpdb;
        
        // Get all records without integrity hash
        $records = $wpdb->get_results(
            "SELECT * FROM {$this->table_name} 
             WHERE integrity_hash IS NULL OR integrity_hash = ''"
        );
        
        foreach ($records as $record) {
            $integrity_hash = $this->generate_integrity_hash(
                $record->user_id,
                $record->credits_used,
                $record->last_generation_date ?: $record->created_at
            );
            
            $wpdb->update(
                $this->table_name,
                array('integrity_hash' => $integrity_hash),
                array('id' => $record->id),
                array('%s'),
                array('%d')
            );
        }
    }
    
    /**
     * Check if site is running on WordPress Playground
     * 
     * @return bool True if on playground domain
     */
    private function is_wordpress_playground() {
        $site_url = site_url();
        $home_url = home_url();
        
        // Check for playground domains
        $playground_domains = array(
            'playground.wordpress.net',
            'wordpress.net/playground',
            'playground.wordpress.com',
            'wordpress.com/playground'
        );
        
        foreach ($playground_domains as $domain) {
            if (strpos($site_url, $domain) !== false || strpos($home_url, $domain) !== false) {
                return true;
            }
        }
        
        // Also check server variables for playground indicators
        if (isset($_SERVER['HTTP_HOST'])) {
            $host = sanitize_text_field(wp_unslash($_SERVER['HTTP_HOST']));
            foreach ($playground_domains as $domain) {
                if (strpos($host, $domain) !== false) {
                    return true;
                }
            }
        }
        
        return false;
    }
}