<?php

/**
 * Software Distribution Manager
 *
 * Handles software versioning, downloads, and update checking.
 *
 * @package WooNooW\Modules\Software
 */

namespace WooNooW\Modules\Software;

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

use WooNooW\Core\ModuleRegistry;
use WooNooW\Modules\Licensing\LicenseManager;

class SoftwareManager
{
    private static $versions_table = 'woonoow_software_versions';
    private static $downloads_table = 'woonoow_software_downloads';

    /**
     * Initialize
     */
    public static function init()
    {
        if (!ModuleRegistry::is_enabled('software')) {
            return;
        }

        // Nothing to hook yet - API endpoints handle requests
    }

    /**
     * Create database tables
     */
    public static function create_tables()
    {
        global $wpdb;
        $charset_collate = $wpdb->get_charset_collate();

        $versions_table = $wpdb->prefix . self::$versions_table;
        $downloads_table = $wpdb->prefix . self::$downloads_table;

        require_once(ABSPATH . 'wp-admin/includes/upgrade.php');

        // Software versions table
        $sql_versions = "CREATE TABLE $versions_table (
            id bigint(20) UNSIGNED NOT NULL AUTO_INCREMENT,
            product_id bigint(20) UNSIGNED NOT NULL,
            version varchar(50) NOT NULL,
            changelog longtext,
            release_date datetime NOT NULL,
            is_current tinyint(1) DEFAULT 0,
            download_count int(11) DEFAULT 0,
            created_at datetime NOT NULL DEFAULT CURRENT_TIMESTAMP,
            PRIMARY KEY  (id),
            KEY idx_product (product_id),
            KEY idx_current (product_id, is_current),
            UNIQUE KEY unique_version (product_id, version)
        ) $charset_collate;";

        dbDelta($sql_versions);

        // Download tokens table (for secure downloads)
        $sql_downloads = "CREATE TABLE $downloads_table (
            id bigint(20) UNSIGNED NOT NULL AUTO_INCREMENT,
            token varchar(64) NOT NULL,
            license_id bigint(20) UNSIGNED NOT NULL,
            product_id bigint(20) UNSIGNED NOT NULL,
            version_id bigint(20) UNSIGNED,
            ip_address varchar(45),
            expires_at datetime NOT NULL,
            used_at datetime DEFAULT NULL,
            created_at datetime NOT NULL DEFAULT CURRENT_TIMESTAMP,
            PRIMARY KEY  (id),
            UNIQUE KEY token (token),
            KEY license_id (license_id),
            KEY expires_at (expires_at)
        ) $charset_collate;";

        dbDelta($sql_downloads);
    }

    /**
     * Get product software configuration
     */
    public static function get_product_config($product_id)
    {
        $enabled = get_post_meta($product_id, '_woonoow_software_enabled', true) === 'yes';

        if (!$enabled) {
            return null;
        }

        return [
            'enabled' => true,
            'slug' => get_post_meta($product_id, '_woonoow_software_slug', true),
            'current_version' => get_post_meta($product_id, '_woonoow_software_current_version', true),
            'wp_enabled' => get_post_meta($product_id, '_woonoow_software_wp_enabled', true) === 'yes',
            'requires_wp' => get_post_meta($product_id, '_woonoow_software_requires_wp', true),
            'tested_wp' => get_post_meta($product_id, '_woonoow_software_tested_wp', true),
            'requires_php' => get_post_meta($product_id, '_woonoow_software_requires_php', true),
            'icon' => get_post_meta($product_id, '_woonoow_software_icon', true),
            'banner' => get_post_meta($product_id, '_woonoow_software_banner', true),
        ];
    }

    /**
     * Get product by software slug
     */
    public static function get_product_by_slug($slug)
    {
        global $wpdb;

        $product_id = $wpdb->get_var($wpdb->prepare(
            "SELECT post_id FROM {$wpdb->postmeta} 
             WHERE meta_key = '_woonoow_software_slug' AND meta_value = %s 
             LIMIT 1",
            $slug
        ));

        return $product_id ? wc_get_product($product_id) : null;
    }

    /**
     * Check for updates
     */
    public static function check_update($license_key, $slug, $current_version)
    {
        // Validate license
        $license_validation = LicenseManager::validate($license_key);

        if (!$license_validation['valid']) {
            return [
                'success' => false,
                'error' => $license_validation['error'] ?? 'invalid_license',
                'message' => $license_validation['message'] ?? __('Invalid license key', 'woonoow'),
            ];
        }

        // Get product by slug
        $product = self::get_product_by_slug($slug);

        if (!$product) {
            return [
                'success' => false,
                'error' => 'product_not_found',
                'message' => __('Software product not found', 'woonoow'),
            ];
        }

        $config = self::get_product_config($product->get_id());

        if (!$config || !$config['enabled']) {
            return [
                'success' => false,
                'error' => 'software_disabled',
                'message' => __('Software distribution is not enabled for this product', 'woonoow'),
            ];
        }

        $latest_version = $config['current_version'];
        $update_available = version_compare($current_version, $latest_version, '<');

        // Get changelog for latest version
        $changelog = self::get_version_changelog($product->get_id(), $latest_version);

        // Build response
        $response = [
            'success' => true,
            'update_available' => $update_available,
            'product' => [
                'name' => $product->get_name(),
                'slug' => $config['slug'],
            ],
            'current_version' => $current_version,
            'latest_version' => $latest_version,
            'changelog' => $changelog['changelog'] ?? '',
            'release_date' => $changelog['release_date'] ?? null,
        ];

        // Add download URL if update available
        if ($update_available) {
            $license = LicenseManager::get_license_by_key($license_key);
            $token = self::generate_download_token($license['id'], $product->get_id());
            $response['download_url'] = rest_url('woonoow/v1/software/download') . '?token=' . $token;
            $response['changelog_url'] = rest_url('woonoow/v1/software/changelog') . '?slug=' . $config['slug'];
        }

        // Add WordPress-specific fields if enabled
        if ($config['wp_enabled']) {
            $response['wordpress'] = [
                'requires' => $config['requires_wp'] ?: null,
                'tested' => $config['tested_wp'] ?: null,
                'requires_php' => $config['requires_php'] ?: null,
            ];

            // Add icons/banners if set
            if ($config['icon']) {
                $icon_url = is_numeric($config['icon'])
                    ? wp_get_attachment_url($config['icon'])
                    : $config['icon'];
                $response['wordpress']['icons'] = [
                    '1x' => $icon_url,
                    '2x' => $icon_url,
                ];
            }

            if ($config['banner']) {
                $banner_url = is_numeric($config['banner'])
                    ? wp_get_attachment_url($config['banner'])
                    : $config['banner'];
                $response['wordpress']['banners'] = [
                    'low' => $banner_url,
                    'high' => $banner_url,
                ];
            }
        }

        return $response;
    }

    /**
     * Get version changelog
     */
    public static function get_version_changelog($product_id, $version = null)
    {
        global $wpdb;
        $table = $wpdb->prefix . self::$versions_table;

        if ($version) {
            return $wpdb->get_row($wpdb->prepare(
                "SELECT version, changelog, release_date FROM $table 
                 WHERE product_id = %d AND version = %s",
                $product_id,
                $version
            ), ARRAY_A);
        }

        // Get current version
        return $wpdb->get_row($wpdb->prepare(
            "SELECT version, changelog, release_date FROM $table 
             WHERE product_id = %d AND is_current = 1",
            $product_id
        ), ARRAY_A);
    }

    /**
     * Get all versions for a product
     */
    public static function get_all_versions($product_id)
    {
        global $wpdb;
        $table = $wpdb->prefix . self::$versions_table;

        return $wpdb->get_results($wpdb->prepare(
            "SELECT * FROM $table WHERE product_id = %d ORDER BY release_date DESC",
            $product_id
        ), ARRAY_A);
    }

    /**
     * Add new version
     */
    public static function add_version($product_id, $version, $changelog, $set_current = true)
    {
        global $wpdb;
        $table = $wpdb->prefix . self::$versions_table;

        // Check if version already exists
        $exists = $wpdb->get_var($wpdb->prepare(
            "SELECT id FROM $table WHERE product_id = %d AND version = %s",
            $product_id,
            $version
        ));

        if ($exists) {
            return new \WP_Error('version_exists', __('Version already exists', 'woonoow'));
        }

        // If setting as current, unset previous current
        if ($set_current) {
            $wpdb->update(
                $table,
                ['is_current' => 0],
                ['product_id' => $product_id]
            );
        }

        // Insert new version
        $wpdb->insert($table, [
            'product_id' => $product_id,
            'version' => $version,
            'changelog' => $changelog,
            'release_date' => current_time('mysql'),
            'is_current' => $set_current ? 1 : 0,
        ]);

        // Update product meta
        if ($set_current) {
            update_post_meta($product_id, '_woonoow_software_current_version', $version);
        }

        do_action('woonoow/software/version_added', $wpdb->insert_id, $product_id, $version);

        return $wpdb->insert_id;
    }

    /**
     * Generate secure download token
     */
    public static function generate_download_token($license_id, $product_id, $version_id = null)
    {
        global $wpdb;
        $table = $wpdb->prefix . self::$downloads_table;

        $token = bin2hex(random_bytes(32));
        $expires_at = gmdate('Y-m-d H:i:s', time() + 300); // 5 minutes

        $wpdb->insert($table, [
            'token' => $token,
            'license_id' => $license_id,
            'product_id' => $product_id,
            'version_id' => $version_id,
            'ip_address' => $_SERVER['REMOTE_ADDR'] ?? null,
            'expires_at' => $expires_at,
        ]);

        return $token;
    }

    /**
     * Validate and consume download token
     */
    public static function validate_download_token($token)
    {
        global $wpdb;
        $table = $wpdb->prefix . self::$downloads_table;

        $download = $wpdb->get_row($wpdb->prepare(
            "SELECT * FROM $table WHERE token = %s AND used_at IS NULL AND expires_at > %s",
            $token,
            current_time('mysql')
        ), ARRAY_A);

        if (!$download) {
            return new \WP_Error('invalid_token', __('Invalid or expired download token', 'woonoow'));
        }

        // Mark as used
        $wpdb->update(
            $table,
            ['used_at' => current_time('mysql')],
            ['id' => $download['id']]
        );

        // Increment download count
        $versions_table = $wpdb->prefix . self::$versions_table;
        if ($download['version_id']) {
            $wpdb->query($wpdb->prepare(
                "UPDATE $versions_table SET download_count = download_count + 1 WHERE id = %d",
                $download['version_id']
            ));
        }

        return $download;
    }

    /**
     * Get downloadable file for product
     * Uses WooCommerce's existing downloadable files
     */
    public static function get_downloadable_file($product_id)
    {
        $product = wc_get_product($product_id);

        if (!$product || !$product->is_downloadable()) {
            return null;
        }

        $downloads = $product->get_downloads();

        if (empty($downloads)) {
            return null;
        }

        // Return first downloadable file
        $download = reset($downloads);

        return [
            'id' => $download->get_id(),
            'name' => $download->get_name(),
            'file' => $download->get_file(),
        ];
    }

    /**
     * Serve downloadable file
     */
    public static function serve_file($product_id)
    {
        $file_data = self::get_downloadable_file($product_id);

        if (!$file_data) {
            wp_die(__('No downloadable file found', 'woonoow'), '', ['response' => 404]);
        }

        $file_path = $file_data['file'];

        // Handle different file types
        if (strpos($file_path, home_url()) === 0) {
            // Local file - convert URL to path
            $upload_dir = wp_upload_dir();
            $file_path = str_replace($upload_dir['baseurl'], $upload_dir['basedir'], $file_path);
        }

        if (!file_exists($file_path)) {
            // Try as attachment
            $file_path = get_attached_file(attachment_url_to_postid($file_data['file']));
        }

        if (!$file_path || !file_exists($file_path)) {
            wp_die(__('File not found', 'woonoow'), '', ['response' => 404]);
        }

        // Serve file
        $filename = basename($file_path);
        $mime_type = mime_content_type($file_path) ?: 'application/octet-stream';

        header('Content-Type: ' . $mime_type);
        header('Content-Disposition: attachment; filename="' . $filename . '"');
        header('Content-Length: ' . filesize($file_path));
        header('Cache-Control: no-cache, must-revalidate');
        header('Pragma: no-cache');
        header('Expires: 0');

        readfile($file_path);
        exit;
    }

    /**
     * Clean up expired tokens
     */
    public static function cleanup_expired_tokens()
    {
        global $wpdb;
        $table = $wpdb->prefix . self::$downloads_table;

        $wpdb->query($wpdb->prepare(
            "DELETE FROM $table WHERE expires_at < %s",
            current_time('mysql')
        ));
    }
}
