<?php
/**
 * Plugin Name: Maple Code Blocks
 * Plugin URI: https://sspmedia.ca/wordpress/
 * Description: Display code files from GitHub, GitLab, Bitbucket, and Codeberg repositories in a beautiful, safe terminal/IDE-style view
 * Version: 2.0.0
 * Author: SSP Media
 * Author URI: https://sspmedia.ca/wordpress/
 * License: GPL v2 or later
 * Text Domain: maple-code-blocks
 */

// Prevent direct access
if (!defined('WPINC')) {
    die('Direct access not permitted.');
}

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

// Define plugin constants
define('MCB_PLUGIN_URL', plugin_dir_url(__FILE__));
define('MCB_PLUGIN_PATH', plugin_dir_path(__FILE__));
define('MCB_PLUGIN_VERSION', '2.0.0');
define('MCB_PLUGIN_BASENAME', plugin_basename(__FILE__));

// Include required files
require_once MCB_PLUGIN_PATH . 'includes/class-security.php';
require_once MCB_PLUGIN_PATH . 'includes/class-security-fixes.php';
require_once MCB_PLUGIN_PATH . 'includes/class-privacy-manager.php';
require_once MCB_PLUGIN_PATH . 'includes/class-github-api.php';
require_once MCB_PLUGIN_PATH . 'includes/class-code-renderer.php';
require_once MCB_PLUGIN_PATH . 'includes/class-shortcode.php';
require_once MCB_PLUGIN_PATH . 'includes/class-simple-block.php';
require_once MCB_PLUGIN_PATH . 'includes/basic-block.php';
// require_once MCB_PLUGIN_PATH . 'includes/class-block-editor.php';
// require_once MCB_PLUGIN_PATH . 'includes/class-block-patterns.php';

// Initialize plugin
class Maple_Code_Blocks {
    
    private static $instance = null;
    
    public static function get_instance() {
        if (null === self::$instance) {
            self::$instance = new self();
        }
        return self::$instance;
    }
    
    private function __construct() {
        add_action('init', array($this, 'init'));
        add_action('wp_enqueue_scripts', array($this, 'enqueue_scripts'));
        add_action('wp_ajax_mcb_load_file', array($this, 'ajax_load_file'));
        add_action('wp_ajax_nopriv_mcb_load_file', array($this, 'ajax_load_file'));
        add_action('wp_ajax_mcb_get_repo_files', array($this, 'ajax_get_repo_files'));
        add_action('wp_ajax_nopriv_mcb_get_repo_files', array($this, 'ajax_get_repo_files'));
    }
    
    public function init() {
        // Initialize shortcode
        MCB_Shortcode::init();

        // Simple block is self-initializing via class-simple-block.php

        // Add admin menu if needed
        if (is_admin()) {
            add_action('admin_menu', array($this, 'add_admin_menu'));
        }
    }
    
    public function enqueue_scripts() {
        // Load styles
        wp_enqueue_style('prism-css', MCB_PLUGIN_URL . 'assets/css/prism.css', array(), MCB_PLUGIN_VERSION);
        wp_enqueue_style('mcb-styles', MCB_PLUGIN_URL . 'assets/css/mcb-styles.css', array(), MCB_PLUGIN_VERSION);
        
        // Load scripts
        wp_enqueue_script('prism-core', MCB_PLUGIN_URL . 'assets/js/prism.js', array(), MCB_PLUGIN_VERSION, true);
        wp_enqueue_script('mcb-script', MCB_PLUGIN_URL . 'assets/js/mcb-script.js', array('jquery'), MCB_PLUGIN_VERSION, true);
        
        // Localize script for AJAX
        wp_localize_script('mcb-script', 'mcb_ajax', array(
            'ajax_url' => admin_url('admin-ajax.php'),
            'nonce' => wp_create_nonce('mcb_ajax_nonce')
        ));
    }
    
    public function ajax_load_file() {
        // Check request method
        if ($_SERVER['REQUEST_METHOD'] !== 'POST') {
            wp_die('Invalid request method', 405);
        }
        
        // Rate limiting check
        if (class_exists('MCB_Privacy_Manager') && MCB_Privacy_Manager::is_privacy_mode()) {
            // Use nonce-based rate limiting in privacy mode
            $rate_limit_key = 'mcb_rate_' . wp_get_current_user()->ID . '_' . wp_create_nonce('mcb_rate');
        } else {
            // IP-based rate limiting
            $user_ip = $this->get_client_ip();
            $rate_limit_key = 'mcb_rate_' . md5($user_ip);
        }
        
        $requests = get_transient($rate_limit_key);
        
        if ($requests !== false && $requests > 30) { // 30 requests per minute
            wp_die('Rate limit exceeded. Please try again later.', 429);
        }
        
        set_transient($rate_limit_key, ($requests ? $requests + 1 : 1), 60);
        
        // Verify nonce
        if (!isset($_POST['nonce']) || !wp_verify_nonce($_POST['nonce'], 'mcb_ajax_nonce')) {
            wp_die('Security check failed', 403);
        }
        
        // Note: We allow public viewing of public repositories by default
        // Site admins can restrict access if needed via filter
        $require_login = apply_filters('mcb_require_login_for_viewing', false);
        
        if ($require_login && !is_user_logged_in()) {
            wp_die('Please log in to view code repositories', 403);
        }
        
        $repo = isset($_POST['repo']) ? sanitize_text_field($_POST['repo']) : '';
        $file_path = isset($_POST['file_path']) ? sanitize_text_field($_POST['file_path']) : '';
        
        // Additional validation using security class
        if (!MCB_Security::validate_repo_format($repo)) {
            MCB_Security::log_security_event('invalid_repo_format', array('repo' => $repo));
            wp_send_json_error('Invalid repository format');
            return;
        }
        
        if (!MCB_Security::validate_file_path($file_path)) {
            MCB_Security::log_security_event('invalid_file_path', array('path' => $file_path));
            wp_send_json_error('Invalid file path');
            return;
        }
        
        $github_api = new MCB_GitHub_API();
        $content = $github_api->get_file_content($repo, $file_path);

        if (is_wp_error($content)) {
            wp_send_json_error($content->get_error_message());
            return;
        }

        // Validate content before sending
        $renderer = new MCB_Code_Renderer();
        $validation = $renderer->validate_content($content);

        if (is_wp_error($validation)) {
            wp_send_json_error($validation->get_error_message());
            return;
        }

        // Return raw content - JavaScript will handle escaping and rendering
        // This is more secure as it avoids double-escaping issues
        wp_send_json_success(array(
            'content' => $content,  // Send raw content, not rendered HTML
            'filename' => basename($file_path)
        ));
    }
    
    public function ajax_get_repo_files() {
        // Check request method
        if ($_SERVER['REQUEST_METHOD'] !== 'POST') {
            wp_die('Invalid request method', 405);
        }

        // Rate limiting check
        $user_ip = $this->get_client_ip();
        $rate_limit_key = 'mcb_rate_' . md5($user_ip);
        $requests = get_transient($rate_limit_key);

        if ($requests !== false && $requests > 30) { // 30 requests per minute
            wp_die('Rate limit exceeded. Please try again later.', 429);
        }

        set_transient($rate_limit_key, ($requests ? $requests + 1 : 1), 60);

        // Verify nonce
        if (!isset($_POST['nonce']) || !wp_verify_nonce($_POST['nonce'], 'mcb_ajax_nonce')) {
            wp_die('Security check failed', 403);
        }
        
        // Note: We allow public viewing of public repositories by default
        // Site admins can restrict access if needed via filter
        $require_login = apply_filters('mcb_require_login_for_viewing', false);
        
        if ($require_login && !is_user_logged_in()) {
            wp_die('Please log in to view code repositories', 403);
        }
        
        $repo = isset($_POST['repo']) ? sanitize_text_field($_POST['repo']) : '';
        $path = isset($_POST['path']) ? sanitize_text_field($_POST['path']) : '';

        // Validate repository format
        if (!MCB_Security::validate_repo_format($repo)) {
            wp_send_json_error('Invalid repository format');
            return;
        }

        $github_api = new MCB_GitHub_API();
        $files = $github_api->get_repository_files($repo, $path);

        if (is_wp_error($files)) {
            wp_send_json_error($files->get_error_message());
            return;
        }

        wp_send_json_success($files);
    }
    
    public function add_admin_menu() {
        add_options_page(
            'GitHub Code Viewer Settings',
            'GitHub Code Viewer',
            'manage_options',
            'maple-code-blocks',
            array($this, 'admin_page')
        );
    }
    
    public function admin_page() {
        include MCB_PLUGIN_PATH . 'admin/settings-page.php';
    }
    
    /**
     * Get client IP address for rate limiting
     */
    private function get_client_ip() {
        $ip_keys = array('HTTP_CF_CONNECTING_IP', 'HTTP_CLIENT_IP', 'HTTP_X_FORWARDED_FOR', 'REMOTE_ADDR');
        foreach ($ip_keys as $key) {
            if (array_key_exists($key, $_SERVER) === true) {
                $ips = explode(',', $_SERVER[$key]);
                foreach ($ips as $ip) {
                    $ip = trim($ip);
                    if (filter_var($ip, FILTER_VALIDATE_IP, 
                        FILTER_FLAG_NO_PRIV_RANGE | FILTER_FLAG_NO_RES_RANGE) !== false) {
                        return $ip;
                    }
                }
            }
        }
        return isset($_SERVER['REMOTE_ADDR']) ? $_SERVER['REMOTE_ADDR'] : '0.0.0.0';
    }
}

// Initialize the plugin
Maple_Code_Blocks::get_instance();

// Register deactivation hook to clean up scheduled events
register_deactivation_hook(__FILE__, 'mcb_deactivate');
function mcb_deactivate() {
    // Remove scheduled cleanup event
    $timestamp = wp_next_scheduled('mcb_privacy_cleanup');
    if ($timestamp) {
        wp_unschedule_event($timestamp, 'mcb_privacy_cleanup');
    }
    
    // Clear all MCB transients
    global $wpdb;
    $wpdb->query("DELETE FROM {$wpdb->options} WHERE option_name LIKE '_transient_mcb_%'");
    $wpdb->query("DELETE FROM {$wpdb->options} WHERE option_name LIKE '_transient_timeout_mcb_%'");
}

// Register uninstall hook for complete cleanup
register_uninstall_hook(__FILE__, 'mcb_uninstall');
function mcb_uninstall() {
    // Remove all plugin options
    delete_option('mcb_settings');
    delete_option('mcb_github_token_encrypted');
    delete_option('mcb_gitlab_token_encrypted');
    delete_option('mcb_bitbucket_token_encrypted');
    delete_option('mcb_codeberg_token_encrypted');
    
    // Clear all transients
    global $wpdb;
    $wpdb->query("DELETE FROM {$wpdb->options} WHERE option_name LIKE '_transient_mcb_%'");
    $wpdb->query("DELETE FROM {$wpdb->options} WHERE option_name LIKE '_transient_timeout_mcb_%'");
    $wpdb->query("DELETE FROM {$wpdb->options} WHERE option_name LIKE '_site_transient_mcb_%'");
    $wpdb->query("DELETE FROM {$wpdb->options} WHERE option_name LIKE '_site_transient_timeout_mcb_%'");
}
