<?php
namespace IntentDeep\VirtualFiles\Controllers;

use IntentDeep\VirtualFiles\Core\Option;
use IntentDeep\VirtualFiles\Core\Cache;
use IntentDeep\VirtualFiles\Traits\SettingHelper;
use IntentDeep\VirtualFiles\Traits\AnalyticsHelper;

class FrontendController {
    use SettingHelper;
    use AnalyticsHelper;

    /**
     * @var Cache
     */
    private $cache;

    public function __construct() {
        $this->cache = new Cache();
        $this->init_hooks();
    }

    /**
     * Initialize WordPress hooks
     */
    public function init_hooks(): void {
        // Only hook if routing is enabled - when disabled, plugin should not interfere at all
        if ($this->is_routing_enabled()) {
            add_action('init', [$this, 'register_rewrite_rules'], 1);
            add_action('template_redirect', [$this, 'handle_virtual_file_request'], 1);
            add_action('template_redirect', [$this, 'prevent_canonical_redirect'], 0);
            add_filter('query_vars', [$this, 'add_query_vars']);

            // Add template filter for virtual files
            add_filter('template_include', [$this, 'handle_virtual_file_template']);
        }
    }

    /**
     * Add custom query variables
     */
    public function add_query_vars($query_vars) {
        $query_vars[] = 'idep_virtual_file';
        $query_vars[] = 'file_id';
        return $query_vars;
    }

    /**
     * Register rewrite rules for virtual files
     */
    public function register_rewrite_rules(): void {
        // Get all active virtual files
        $virtual_files = $this->get_active_virtual_files();

        foreach ($virtual_files as $file) {
            $filename = get_post_meta($file->ID, '_vf_filename', true);
            if (!empty($filename)) {
                // Sanitize filename for rewrite rule
                $safe_filename = preg_quote($filename, '/');

                // Create rewrite rule for exact filename without trailing slash
                add_rewrite_rule(
                    '^' . $safe_filename . '$',
                    'index.php?idep_virtual_file=1&file_id=' . intval($file->ID),
                    'top'
                );

                // Create separate rule for with trailing slash
                add_rewrite_rule(
                    '^' . $safe_filename . '/$',
                    'index.php?idep_virtual_file=1&file_id=' . intval($file->ID),
                    'top'
                );
            }
        }
    }

    /**
     * Handle virtual file request
     */
    public function handle_virtual_file_request(): void {
        intentdeep_vf_log('Virtual Files: handle_virtual_file_request called');
        intentdeep_vf_log('Virtual Files: Request URI: ' . (isset($_SERVER['REQUEST_URI']) ? sanitize_text_field(wp_unslash($_SERVER['REQUEST_URI'])) : ''));
        intentdeep_vf_log('Virtual Files: Query vars: ' . print_r($GLOBALS['wp']->query_vars, true));

        $virtual_file = get_query_var('idep_virtual_file');
        $file_id = intval(get_query_var('file_id'));

        intentdeep_vf_log('Virtual Files: virtual_file query var: ' . $virtual_file);
        intentdeep_vf_log('Virtual Files: file_id query var: ' . $file_id);

        if ($virtual_file && $file_id > 0) {
            intentdeep_vf_log('Virtual Files: Calling serve_virtual_file for file ID: ' . $file_id);
            $this->serve_virtual_file($file_id);
            exit;
        } else {
            intentdeep_vf_log('Virtual Files: No virtual file request detected');
        }
    }

    /**
     * Serve virtual file content
     */
    private function serve_virtual_file(int $file_id): void {
        $post = get_post($file_id);

        if (!$post || $post->post_type !== 'idep_virtual_file') {
            $this->send_404(__('Virtual file not found', 'intentdeep-virtual-files'));
            return;
        }

        // Check if file is active
        $status = get_post_meta($post->ID, '_vf_status', true);
        if ($status !== 'active') {
            $this->send_404(__('Virtual file is inactive', 'intentdeep-virtual-files'));
            return;
        }

        // Check if user has valid license or can use premium features
        $user_has_pro = function_exists('intentdeep_vf_fs') && intentdeep_vf_fs()->can_use_premium_code__premium_only();
        intentdeep_vf_log('Virtual Files: Frontend check - User has Pro: ' . ($user_has_pro ? 'YES' : 'NO'));

        // If user doesn't have Pro, check file limit
        if (!$user_has_pro) {
            intentdeep_vf_log('Virtual Files: Frontend check - User is free user, checking file limit for file ID: ' . $post->ID);
            if (!$this->isFileAccessibleForFreeUser($post->ID)) {
                intentdeep_vf_log('Virtual Files: Frontend check - Blocking file access for free user');
                $this->send_404(__('Virtual file access limited. Upgrade to Pro for unlimited file access.', 'intentdeep-virtual-files'));
                return;
            }
            intentdeep_vf_log('Virtual Files: Frontend check - Allowing file access for free user');
        } else {
            intentdeep_vf_log('Virtual Files: Frontend check - User has Pro, allowing all files');
        }

        // Try to get cached file data first
        $cached_file_data = $this->cache->get_file_cache($file_id);

        if ($cached_file_data !== null) {
            intentdeep_vf_log('Virtual Files: Serving cached file for ID: ' . $file_id);
            // Set proper headers
            $this->set_file_headers($cached_file_data['filename'], $cached_file_data['mime_type'], $cached_file_data['content_length']);

            // Output the cached content
            // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped -- Escaping is not applicable for virtual file content that must be served as raw data (robots.txt, XML sitemaps, JSON-LD, etc.). Security measures: (1) Only users with edit_post capability can create/modify files, (2) Content is sanitized on input via ContentSanitizationHelper::sanitizeVirtualFileContent(), (3) Content is validated before serving via is_safe_content() which blocks PHP tags, script tags, and dangerous functions, (4) Files are served with proper MIME type headers that prevent script execution in browsers.
            echo $cached_file_data['content'];

            // Update access count for pro users
            $this->update_access_stats($file_id);
            return;
        }

        // No cache hit, get file data from database
        $filename = get_post_meta($post->ID, '_vf_filename', true);
        $content = get_post_meta($post->ID, '_vf_content', true);
        $mime_type = get_post_meta($post->ID, '_vf_mime_type', true);

        if (empty($filename) || empty($content)) {
            $this->send_404(__('Virtual file content not found', 'intentdeep-virtual-files'));
            return;
        }

        // Validate content for security
        if (!$this->is_safe_content($content)) {
            $this->send_404(__('Invalid file content', 'intentdeep-virtual-files'));
            return;
        }

        // Cache the file data for future requests
        $file_data = [
            'filename' => $filename,
            'content' => $content,
            'mime_type' => $mime_type,
            'content_length' => strlen($content),
            'cached_at' => current_time('timestamp'),
            'post_modified' => strtotime($post->post_modified_gmt),
        ];
        $this->cache->set_file_cache($file_id, $file_data);

        intentdeep_vf_log('Virtual Files: Serving uncached file and caching for ID: ' . $file_id);

        // Set proper headers
        $this->set_file_headers($filename, $mime_type, strlen($content));

        // Output the content
        // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped -- Escaping is not applicable for virtual file content that must be served as raw data (robots.txt, XML sitemaps, JSON-LD, etc.). Security measures: (1) Only users with edit_post capability can create/modify files, (2) Content is sanitized on input via ContentSanitizationHelper::sanitizeVirtualFileContent(), (3) Content is validated before serving via is_safe_content() which blocks PHP tags, script tags, and dangerous functions, (4) Files are served with proper MIME type headers that prevent script execution in browsers.
        echo $content;

        // Update access count for pro users
        $this->update_access_stats($post->ID);
    }

    /**
     * Check if URL routing is enabled
     */
    private function is_routing_enabled(): bool {
        $settings = $this->getSettings();
        return !empty($settings['routing_enabled']);
    }

    /**
     * Get active virtual files
     */
    private function get_active_virtual_files(): array {
        return get_posts([
            'post_type' => 'idep_virtual_file',
            'posts_per_page' => -1,
            'post_status' => 'publish',
            'meta_query' => [
                [
                    'key' => '_vf_status',
                    'value' => 'active',
                    'compare' => '='
                ],
                [
                    'key' => '_vf_filename',
                    'value' => '',
                    'compare' => '!='
                ]
            ]
        ]);
    }

    /**
     * Check if content is safe to serve
     */
    private function is_safe_content(string $content): bool {
        // Check for PHP code
        if (preg_match('/<\?php/i', $content)) {
            return false;
        }

        // Check for JavaScript (unless it's a JSON file)
        if (preg_match('/<script/i', $content)) {
            return false;
        }

        // Check for potentially dangerous patterns
        $dangerous_patterns = [
            '/\beval\s*\(/i',
            '/\bexec\s*\(/i',
            '/\bsystem\s*\(/i',
            '/\bshell_exec\s*\(/i',
            '/\bpassthru\s*\(/i',
            '/\bfile_get_contents\s*\(/i',
            '/\bfopen\s*\(/i',
            '/\bcurl_exec\s*\(/i'
        ];

        foreach ($dangerous_patterns as $pattern) {
            if (preg_match($pattern, $content)) {
                return false;
            }
        }

        return true;
    }

    /**
     * Set proper file headers
     */
    private function set_file_headers(string $filename, string $mime_type, int $content_length): void {
        // Content type
        header('Content-Type: ' . $mime_type);

        // Content length
        header('Content-Length: ' . $content_length);

        // Cache headers
        header('Cache-Control: public, max-age=3600');
        header('Expires: ' . gmdate('D, d M Y H:i:s \G\M\T', time() + 3600));

        // Accept-Ranges header
        header('Accept-Ranges: bytes');

        // Content disposition (optional - uncomment if you want download behavior)
        // header('Content-Disposition: inline; filename="' . $filename . '"');

        // Security headers
        header('X-Content-Type-Options: nosniff');
        header('X-Frame-Options: SAMEORIGIN');
    }

    /**
     * Update access statistics (Pro feature)
     */
    private function update_access_stats(int $post_id): void {
        // Only update stats for pro users
        if (function_exists('intentdeep_vf_fs') && intentdeep_vf_fs()->can_use_premium_code__premium_only()) {
            // Use enhanced analytics tracking (daily/hourly stats)
            $this->trackFileViewAnalytics($post_id);
        }
    }

    /**
     * Send 404 response
     */
    private function send_404(string $message): void {
        status_header(404);
        nocache_headers();
            wp_die(esc_html($message), esc_html__('Virtual File Not Found', 'intentdeep-virtual-files'), ['response' => 404]);
    }

    /**
     * Prevent WordPress canonical redirects for virtual files
     */
    public function prevent_canonical_redirect(): void {
        if (get_query_var('idep_virtual_file')) {
            remove_action('template_redirect', 'redirect_canonical');
        }
    }

    /**
     * Handle virtual file template - this is the main entry point for serving virtual files
     */
    public function handle_virtual_file_template($template) {
        global $wp_query;

        // Check if this is a virtual_file request
        if ($wp_query->is_single && $wp_query->get('post_type') === 'idep_virtual_file') {
            $post_id = $wp_query->get_queried_object_id();
            intentdeep_vf_log('Virtual Files: Template handler called for post ID: ' . $post_id);

            // Check if user has valid license or can use premium features
            $user_has_pro = function_exists('intentdeep_vf_fs') && intentdeep_vf_fs()->can_use_premium_code__premium_only();
            intentdeep_vf_log('Virtual Files: Template check - User has Pro: ' . ($user_has_pro ? 'YES' : 'NO'));

            // If user doesn't have Pro, check file limit
            if (!$user_has_pro) {
                if (!$this->isFileAccessibleForFreeUser($post_id)) {
                    intentdeep_vf_log('Virtual Files: Template check - Blocking file access for free user');
                    $this->send_404(__('Virtual file access limited. Upgrade to Pro for unlimited file access.', 'intentdeep-virtual-files'));
                    return; // This will exit the script
                }
                intentdeep_vf_log('Virtual Files: Template check - Allowing file access for free user');
            } else {
                intentdeep_vf_log('Virtual Files: Template check - User has Pro, allowing all files');
            }

            // Serve the virtual file
            $this->serve_virtual_file_direct($post_id);
        }

        return $template;
    }

    /**
     * Serve virtual file content directly (simplified version)
     */
    private function serve_virtual_file_direct($post_id) {
        $post = get_post($post_id);

        if (!$post || $post->post_type !== 'idep_virtual_file') {
            $this->send_404(__('Virtual file not found', 'intentdeep-virtual-files'));
            return;
        }

        // Check if file is active
        $status = get_post_meta($post->ID, '_vf_status', true);
        if ($status !== 'active') {
            $this->send_404(__('Virtual file is inactive', 'intentdeep-virtual-files'));
            return;
        }

        // Try to get cached file data first
        $cached_file_data = $this->cache->get_file_cache($post_id);

        if ($cached_file_data !== null) {
            // Set proper headers
            $this->set_file_headers($cached_file_data['filename'], $cached_file_data['mime_type'], $cached_file_data['content_length']);

            // Output the cached content
            // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped -- Escaping is not applicable for virtual file content that must be served as raw data (robots.txt, XML sitemaps, JSON-LD, etc.). Security measures: (1) Only users with edit_post capability can create/modify files, (2) Content is sanitized on input via ContentSanitizationHelper::sanitizeVirtualFileContent(), (3) Content is validated before serving via is_safe_content() which blocks PHP tags, script tags, and dangerous functions, (4) Files are served with proper MIME type headers that prevent script execution in browsers.
            echo $cached_file_data['content'];
            exit;
        }

        // No cache hit, get file data from database
        $filename = get_post_meta($post->ID, '_vf_filename', true);
        $content = get_post_meta($post->ID, '_vf_content', true);
        $mime_type = get_post_meta($post->ID, '_vf_mime_type', true);

        if (empty($filename) || empty($content)) {
            $this->send_404(__('Virtual file content not found', 'intentdeep-virtual-files'));
            return;
        }

        // Validate content for security
        if (!$this->is_safe_content($content)) {
            $this->send_404(__('Invalid file content', 'intentdeep-virtual-files'));
            return;
        }

        // Cache the file data for future requests
        $file_data = [
            'filename' => $filename,
            'content' => $content,
            'mime_type' => $mime_type,
            'content_length' => strlen($content),
            'cached_at' => current_time('timestamp'),
            'post_modified' => strtotime($post->post_modified_gmt),
        ];
        $this->cache->set_file_cache($post_id, $file_data);

        // Set proper headers
        $this->set_file_headers($filename, $mime_type, strlen($content));

        // Output the content
        // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped -- Escaping is not applicable for virtual file content that must be served as raw data (robots.txt, XML sitemaps, JSON-LD, etc.). Security measures: (1) Only users with edit_post capability can create/modify files, (2) Content is sanitized on input via ContentSanitizationHelper::sanitizeVirtualFileContent(), (3) Content is validated before serving via is_safe_content() which blocks PHP tags, script tags, and dangerous functions, (4) Files are served with proper MIME type headers that prevent script execution in browsers.
        echo $content;
        exit;
    }

    /**
     * Check if a file is accessible for free users (max 5 files, newest first)
     */
    private function isFileAccessibleForFreeUser($file_id): bool {
        // Get all active virtual files, ordered by modification date (newest first)
        $all_active_files = get_posts([
            'post_type' => 'idep_virtual_file',
            'posts_per_page' => -1,
            'post_status' => 'publish',
            'meta_query' => [
                [
                    'key' => '_vf_status',
                    'value' => 'active',
                    'compare' => '='
                ]
            ],
            'orderby' => 'meta_value_num', // Sort by modified timestamp
            'meta_key' => '_vf_modified',
            'order' => 'DESC'
        ]);

        intentdeep_vf_log('Virtual Files: Template check - Total active files: ' . count($all_active_files));

        // If 5 or fewer files, all are accessible
        if (count($all_active_files) <= 5) {
            intentdeep_vf_log('Virtual Files: Template check - 5 or fewer files, all accessible');
            return true;
        }

        // Get the first 5 (newest) file IDs
        $accessible_file_ids = array_slice(wp_list_pluck($all_active_files, 'ID'), 0, 5);
        $is_accessible = in_array($file_id, $accessible_file_ids);

        intentdeep_vf_log('Virtual Files: Template check - File ' . $file_id . ' accessible: ' . ($is_accessible ? 'YES' : 'NO'));
        intentdeep_vf_log('Virtual Files: Template check - Accessible file IDs: ' . implode(', ', $accessible_file_ids));

        return $is_accessible;
    }
}