<?php
/**
 * License Manager
 *
 * Handles license key generation, activation, deactivation, and validation.
 *
 * @package WooNooW\Modules\Licensing
 */

namespace WooNooW\Modules\Licensing;

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

use WooNooW\Core\ModuleRegistry;

class LicenseManager {
    
    private static $table_name = 'woonoow_licenses';
    private static $activations_table = 'woonoow_license_activations';
    
    /**
     * Initialize
     */
    public static function init() {
        // Only initialize if module is enabled
        if (!ModuleRegistry::is_enabled('licensing')) {
            return;
        }
        
        // Hook into order completion - multiple hooks to catch all scenarios
        add_action('woocommerce_order_status_completed', [__CLASS__, 'generate_licenses_for_order']);
        add_action('woocommerce_order_status_processing', [__CLASS__, 'generate_licenses_for_order']);
        add_action('woocommerce_payment_complete', [__CLASS__, 'generate_licenses_for_order']);
        
        // Also hook into thank you page for COD/pending orders (with lower priority)
        add_action('woocommerce_thankyou', [__CLASS__, 'maybe_generate_on_thankyou'], 10);
    }
    
    /**
     * Maybe generate licenses on thank you page (for COD and pending orders)
     */
    public static function maybe_generate_on_thankyou($order_id) {
        if (!$order_id) return;
        
        $order = wc_get_order($order_id);
        if (!$order) return;
        
        // Only generate for orders that didn't already get licenses via status hooks
        // Check if it's a virtual-only order that might skip payment completion
        $needs_payment = $order->needs_payment();
        $is_virtual = self::is_virtual_order($order);
        
        // Generate if: virtual order OR already paid (processing/completed) 
        if ($is_virtual || in_array($order->get_status(), ['processing', 'completed'])) {
            self::generate_licenses_for_order($order_id);
        }
    }
    
    /**
     * Check if order contains only virtual items
     */
    private static function is_virtual_order($order) {
        foreach ($order->get_items() as $item) {
            $product = $item->get_product();
            if ($product && !$product->is_virtual()) {
                return false;
            }
        }
        return true;
    }
    
    /**
     * Create database tables
     */
    public static function create_tables() {
        global $wpdb;
        $charset_collate = $wpdb->get_charset_collate();
        
        $licenses_table = $wpdb->prefix . self::$table_name;
        $activations_table = $wpdb->prefix . self::$activations_table;
        
        require_once(ABSPATH . 'wp-admin/includes/upgrade.php');
        
        // Create licenses table - dbDelta requires each CREATE TABLE to be called separately
        $sql_licenses = "CREATE TABLE $licenses_table (
            id bigint(20) UNSIGNED NOT NULL AUTO_INCREMENT,
            license_key varchar(255) NOT NULL,
            product_id bigint(20) UNSIGNED NOT NULL,
            order_id bigint(20) UNSIGNED NOT NULL,
            order_item_id bigint(20) UNSIGNED NOT NULL,
            user_id bigint(20) UNSIGNED NOT NULL,
            status varchar(20) NOT NULL DEFAULT 'active',
            activation_limit int(11) NOT NULL DEFAULT 1,
            activation_count int(11) NOT NULL DEFAULT 0,
            expires_at datetime DEFAULT NULL,
            created_at datetime NOT NULL DEFAULT CURRENT_TIMESTAMP,
            updated_at datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
            PRIMARY KEY  (id),
            UNIQUE KEY license_key (license_key),
            KEY product_id (product_id),
            KEY order_id (order_id),
            KEY user_id (user_id),
            KEY status (status)
        ) $charset_collate;";
        
        dbDelta($sql_licenses);
        
        // Create activations table
        $sql_activations = "CREATE TABLE $activations_table (
            id bigint(20) UNSIGNED NOT NULL AUTO_INCREMENT,
            license_id bigint(20) UNSIGNED NOT NULL,
            domain varchar(255) DEFAULT NULL,
            ip_address varchar(45) DEFAULT NULL,
            machine_id varchar(255) DEFAULT NULL,
            user_agent text DEFAULT NULL,
            status varchar(20) NOT NULL DEFAULT 'active',
            activated_at datetime NOT NULL DEFAULT CURRENT_TIMESTAMP,
            deactivated_at datetime DEFAULT NULL,
            PRIMARY KEY  (id),
            KEY license_id (license_id),
            KEY status (status)
        ) $charset_collate;";
        
        dbDelta($sql_activations);
    }
    
    /**
     * Generate licenses for completed order
     */
    public static function generate_licenses_for_order($order_id) {
        $order = wc_get_order($order_id);
        if (!$order) return;
        
        foreach ($order->get_items() as $item_id => $item) {
            $product_id = $item->get_product_id();
            $product = wc_get_product($product_id);
            
            if (!$product) continue;
            
            // Check if product has licensing enabled
            $licensing_enabled = get_post_meta($product_id, '_woonoow_licensing_enabled', true);
            if ($licensing_enabled !== 'yes') continue;
            
            // Check if license already exists for this order item
            if (self::license_exists_for_order_item($item_id)) continue;
            
            // Get activation limit from product or default
            $activation_limit = (int) get_post_meta($product_id, '_woonoow_license_activation_limit', true);
            if ($activation_limit <= 0) {
                $activation_limit = (int) get_option('woonoow_licensing_default_activation_limit', 1);
            }
            
            // Get expiry from product or default
            $expiry_days = (int) get_post_meta($product_id, '_woonoow_license_expiry_days', true);
            if ($expiry_days <= 0 && get_option('woonoow_licensing_license_expiry_enabled', false)) {
                $expiry_days = (int) get_option('woonoow_licensing_default_expiry_days', 365);
            }
            
            $expires_at = $expiry_days > 0 ? gmdate('Y-m-d H:i:s', strtotime("+$expiry_days days")) : null;
            
            // Generate license for each quantity
            $quantity = $item->get_quantity();
            for ($i = 0; $i < $quantity; $i++) {
                self::create_license([
                    'product_id' => $product_id,
                    'order_id' => $order_id,
                    'order_item_id' => $item_id,
                    'user_id' => $order->get_user_id(),
                    'activation_limit' => $activation_limit,
                    'expires_at' => $expires_at,
                ]);
            }
        }
    }
    
    /**
     * Check if license already exists for order item
     */
    public static function license_exists_for_order_item($order_item_id) {
        global $wpdb;
        $table = $wpdb->prefix . self::$table_name;
        
        return (bool) $wpdb->get_var($wpdb->prepare(
            "SELECT COUNT(*) FROM $table WHERE order_item_id = %d",
            $order_item_id
        ));
    }
    
    /**
     * Create a new license
     */
    public static function create_license($data) {
        global $wpdb;
        $table = $wpdb->prefix . self::$table_name;
        
        $license_key = self::generate_license_key();
        
        $wpdb->insert($table, [
            'license_key' => $license_key,
            'product_id' => $data['product_id'],
            'order_id' => $data['order_id'],
            'order_item_id' => $data['order_item_id'],
            'user_id' => $data['user_id'],
            'activation_limit' => $data['activation_limit'] ?? 1,
            'expires_at' => $data['expires_at'] ?? null,
            'status' => 'active',
        ]);
        
        $license_id = $wpdb->insert_id;
        
        do_action('woonoow/license/created', $license_id, $license_key, $data);
        
        return [
            'id' => $license_id,
            'license_key' => $license_key,
        ];
    }
    
    /**
     * Generate license key
     */
    public static function generate_license_key() {
        $format = get_option('woonoow_licensing_license_key_format', 'serial');
        $prefix = get_option('woonoow_licensing_license_key_prefix', '');
        
        switch ($format) {
            case 'uuid':
                $key = wp_generate_uuid4();
                break;
            case 'alphanumeric':
                $key = strtoupper(wp_generate_password(16, false));
                break;
            case 'serial':
            default:
                $key = strtoupper(sprintf(
                    '%s-%s-%s-%s',
                    wp_generate_password(4, false),
                    wp_generate_password(4, false),
                    wp_generate_password(4, false),
                    wp_generate_password(4, false)
                ));
                break;
        }
        
        return $prefix . $key;
    }
    
    /**
     * Get license by key
     */
    public static function get_license_by_key($license_key) {
        global $wpdb;
        $table = $wpdb->prefix . self::$table_name;
        
        return $wpdb->get_row($wpdb->prepare(
            "SELECT * FROM $table WHERE license_key = %s",
            $license_key
        ), ARRAY_A);
    }
    
    /**
     * Get license by ID
     */
    public static function get_license($license_id) {
        global $wpdb;
        $table = $wpdb->prefix . self::$table_name;
        
        return $wpdb->get_row($wpdb->prepare(
            "SELECT * FROM $table WHERE id = %d",
            $license_id
        ), ARRAY_A);
    }
    
    /**
     * Get licenses for user
     */
    public static function get_user_licenses($user_id, $args = []) {
        global $wpdb;
        $table = $wpdb->prefix . self::$table_name;
        
        $defaults = [
            'status' => null,
            'limit' => 50,
            'offset' => 0,
        ];
        $args = wp_parse_args($args, $defaults);
        
        $where = "user_id = %d";
        $params = [$user_id];
        
        if ($args['status']) {
            $where .= " AND status = %s";
            $params[] = $args['status'];
        }
        
        $sql = "SELECT * FROM $table WHERE $where ORDER BY created_at DESC LIMIT %d OFFSET %d";
        $params[] = $args['limit'];
        $params[] = $args['offset'];
        
        return $wpdb->get_results($wpdb->prepare($sql, $params), ARRAY_A);
    }
    
    /**
     * Activate license
     */
    public static function activate($license_key, $activation_data = []) {
        global $wpdb;
        $license = self::get_license_by_key($license_key);
        
        if (!$license) {
            return new \WP_Error('invalid_license', __('Invalid license key', 'woonoow'));
        }
        
        if ($license['status'] !== 'active') {
            return new \WP_Error('license_inactive', __('License is not active', 'woonoow'));
        }
        
        // Check expiry
        if ($license['expires_at'] && strtotime($license['expires_at']) < time()) {
            $block_expired = get_option('woonoow_licensing_block_expired_activations', true);
            if ($block_expired) {
                return new \WP_Error('license_expired', __('License has expired', 'woonoow'));
            }
        }
        
        // Check activation limit
        if ($license['activation_limit'] > 0 && $license['activation_count'] >= $license['activation_limit']) {
            return new \WP_Error('activation_limit_reached', __('Activation limit reached', 'woonoow'));
        }
        
        // Create activation record
        $activations_table = $wpdb->prefix . self::$activations_table;
        $licenses_table = $wpdb->prefix . self::$table_name;
        
        $wpdb->insert($activations_table, [
            'license_id' => $license['id'],
            'domain' => $activation_data['domain'] ?? null,
            'ip_address' => $activation_data['ip_address'] ?? null,
            'machine_id' => $activation_data['machine_id'] ?? null,
            'user_agent' => $activation_data['user_agent'] ?? null,
            'status' => 'active',
        ]);
        
        // Increment activation count
        $wpdb->query($wpdb->prepare(
            "UPDATE $licenses_table SET activation_count = activation_count + 1 WHERE id = %d",
            $license['id']
        ));
        
        do_action('woonoow/license/activated', $license['id'], $activation_data);
        
        return [
            'success' => true,
            'activation_id' => $wpdb->insert_id,
            'activations_remaining' => $license['activation_limit'] > 0 
                ? max(0, $license['activation_limit'] - $license['activation_count'] - 1)
                : -1,
        ];
    }
    
    /**
     * Deactivate license
     */
    public static function deactivate($license_key, $activation_id = null, $machine_id = null) {
        global $wpdb;
        $license = self::get_license_by_key($license_key);
        
        if (!$license) {
            return new \WP_Error('invalid_license', __('Invalid license key', 'woonoow'));
        }
        
        // Check if deactivation is allowed
        $allow_deactivation = get_option('woonoow_licensing_allow_deactivation', true);
        if (!$allow_deactivation) {
            return new \WP_Error('deactivation_disabled', __('License deactivation is disabled', 'woonoow'));
        }
        
        $activations_table = $wpdb->prefix . self::$activations_table;
        $licenses_table = $wpdb->prefix . self::$table_name;
        
        // Find activation to deactivate
        $where = "license_id = %d AND status = 'active'";
        $params = [$license['id']];
        
        if ($activation_id) {
            $where .= " AND id = %d";
            $params[] = $activation_id;
        } elseif ($machine_id) {
            $where .= " AND machine_id = %s";
            $params[] = $machine_id;
        }
        
        $activation = $wpdb->get_row($wpdb->prepare(
            "SELECT * FROM $activations_table WHERE $where LIMIT 1",
            $params
        ), ARRAY_A);
        
        if (!$activation) {
            return new \WP_Error('no_activation', __('No active activation found', 'woonoow'));
        }
        
        // Deactivate
        $wpdb->update(
            $activations_table,
            ['status' => 'deactivated', 'deactivated_at' => current_time('mysql')],
            ['id' => $activation['id']]
        );
        
        // Decrement activation count
        $wpdb->query($wpdb->prepare(
            "UPDATE $licenses_table SET activation_count = GREATEST(0, activation_count - 1) WHERE id = %d",
            $license['id']
        ));
        
        do_action('woonoow/license/deactivated', $license['id'], $activation['id']);
        
        return ['success' => true];
    }
    
    /**
     * Validate license (check if valid without activating)
     */
    public static function validate($license_key) {
        $license = self::get_license_by_key($license_key);
        
        if (!$license) {
            return [
                'valid' => false,
                'error' => 'invalid_license',
                'message' => __('Invalid license key', 'woonoow'),
            ];
        }
        
        $is_expired = $license['expires_at'] && strtotime($license['expires_at']) < time();
        
        return [
            'valid' => $license['status'] === 'active' && !$is_expired,
            'license_key' => $license['license_key'],
            'status' => $license['status'],
            'activation_limit' => (int) $license['activation_limit'],
            'activation_count' => (int) $license['activation_count'],
            'activations_remaining' => $license['activation_limit'] > 0 
                ? max(0, $license['activation_limit'] - $license['activation_count'])
                : -1,
            'expires_at' => $license['expires_at'],
            'is_expired' => $is_expired,
        ];
    }
    
    /**
     * Revoke license
     */
    public static function revoke($license_id) {
        global $wpdb;
        $table = $wpdb->prefix . self::$table_name;
        
        $result = $wpdb->update(
            $table,
            ['status' => 'revoked'],
            ['id' => $license_id]
        );
        
        if ($result !== false) {
            do_action('woonoow/license/revoked', $license_id);
            return true;
        }
        
        return false;
    }
    
    /**
     * Get all licenses (admin)
     */
    public static function get_all_licenses($args = []) {
        global $wpdb;
        $table = $wpdb->prefix . self::$table_name;
        
        $defaults = [
            'search' => '',
            'status' => null,
            'product_id' => null,
            'user_id' => null,
            'limit' => 50,
            'offset' => 0,
            'orderby' => 'created_at',
            'order' => 'DESC',
        ];
        $args = wp_parse_args($args, $defaults);
        
        $where_clauses = ['1=1'];
        $params = [];
        
        if ($args['search']) {
            $where_clauses[] = "license_key LIKE %s";
            $params[] = '%' . $wpdb->esc_like($args['search']) . '%';
        }
        
        if ($args['status']) {
            $where_clauses[] = "status = %s";
            $params[] = $args['status'];
        }
        
        if ($args['product_id']) {
            $where_clauses[] = "product_id = %d";
            $params[] = $args['product_id'];
        }
        
        if ($args['user_id']) {
            $where_clauses[] = "user_id = %d";
            $params[] = $args['user_id'];
        }
        
        $where = implode(' AND ', $where_clauses);
        $orderby = sanitize_sql_orderby($args['orderby'] . ' ' . $args['order']) ?: 'created_at DESC';
        
        $sql = "SELECT * FROM $table WHERE $where ORDER BY $orderby LIMIT %d OFFSET %d";
        $params[] = $args['limit'];
        $params[] = $args['offset'];
        
        $licenses = $wpdb->get_results($wpdb->prepare($sql, $params), ARRAY_A);
        
        // Get total count
        $count_sql = "SELECT COUNT(*) FROM $table WHERE $where";
        $total = $wpdb->get_var($wpdb->prepare($count_sql, array_slice($params, 0, -2)));
        
        return [
            'licenses' => $licenses,
            'total' => (int) $total,
        ];
    }
    
    /**
     * Get activations for a license
     */
    public static function get_activations($license_id) {
        global $wpdb;
        $table = $wpdb->prefix . self::$activations_table;
        
        return $wpdb->get_results($wpdb->prepare(
            "SELECT * FROM $table WHERE license_id = %d ORDER BY activated_at DESC",
            $license_id
        ), ARRAY_A);
    }
}
