<?php
/**
 * Shortcode Handler
 *
 * @package Spin_Wheel
 */

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

/**
 * SWP_Shortcode Class
 */
class SWP_Shortcode {
    
    /**
     * Instance
     *
     * @var SWP_Shortcode
     */
    private static $instance = null;
    
    /**
     * Wheel IDs already rendered this request (skip duplicate auto-embed in footer).
     *
     * @var int[]
     */
    private static $rendered_wheel_ids = [];
    
    /**
     * Get instance
     *
     * @return SWP_Shortcode
     */
    public static function instance() {
        if (is_null(self::$instance)) {
            self::$instance = new self();
        }
        return self::$instance;
    }
    
    /**
     * Constructor
     */
    private function __construct() {
        add_shortcode('spin_wheel', [$this, 'render_shortcode']);
        add_action('wp_enqueue_scripts', [$this, 'maybe_enqueue_auto_embed_assets'], 20);
        // Before wp_print_footer_scripts (20): markup must exist before scripts run if they init synchronously.
        add_action('wp_footer', [$this, 'print_auto_embed_wheel'], 15);
    }
    
    /**
     * Render shortcode
     *
     * @param array $atts Shortcode attributes
     * @return string Shortcode output
     */
    public function render_shortcode($atts) {
        return $this->render_shortcode_inner($atts, true);
    }
    
    /**
     * Core render: optional enqueue (false when assets were already enqueued on wp_enqueue_scripts).
     *
     * @param array $atts Shortcode attributes.
     * @param bool  $enqueue Whether to enqueue CSS/JS.
     * @return string
     */
    private function render_shortcode_inner($atts, $enqueue) {
        $atts = shortcode_atts([
            'id' => 0,
        ], $atts, 'spin_wheel');
        
        $wheel_id = intval($atts['id']);
        
        if (!$wheel_id) {
            return '<p>' . esc_html__('Please provide a valid wheel ID.', 'spin-wheel') . '</p>';
        }

        // Check if wheel exists
        $wheel = get_post($wheel_id);
        if (!$wheel || $wheel->post_type !== 'swp_wheel' || $wheel->post_status !== 'publish') {
            return '<p>' . esc_html__('Wheel not found or not published.', 'spin-wheel') . '</p>';
        }
        
        // Get wheel data
        $wheel_type = get_post_meta($wheel_id, '_swp_wheel_type', true);
        $prizes = get_post_meta($wheel_id, '_swp_prizes', true);
        $settings = get_post_meta($wheel_id, '_swp_settings', true);
        $styles = get_post_meta($wheel_id, '_swp_styles', true);
        $form_settings = get_post_meta($wheel_id, '_swp_form_settings', true);
        
        if (empty($wheel_type) || empty($prizes)) {
            return '<p>' . esc_html__('Wheel is not properly configured.', 'spin-wheel') . '</p>';
        }
        
        // Ensure arrays exist
        if (!is_array($settings)) {
            $settings = [];
        }
        if (!is_array($styles)) {
            $styles = [];
        }
        if (!is_array($form_settings)) {
            $form_settings = [];
        }
        // Apply global defaults to form settings
        $global_settings = get_option('swp_settings', []);
        if (empty($form_settings['button_text'])) {
            $form_settings['button_text'] = $global_settings['default_submit_button_text'] ?? 'Spin Now!';
        }
        $form_settings = swp_normalize_form_settings($form_settings);
        
        // Add wheel mode to settings if not already there
        if (!isset($settings['wheel_mode'])) {
            $wheel_mode = get_post_meta($wheel_id, '_swp_wheel_mode', true);
            $settings['wheel_mode'] = $wheel_mode ?: 'instant';
        }
        
        // Check display rules
        if (!$this->should_display_wheel($settings)) {
            return ''; // Don't display wheel if rules don't match
        }
        
        if ($enqueue) {
            $this->enqueue_assets();
        }
        
        if (!in_array($wheel_id, self::$rendered_wheel_ids, true)) {
            self::$rendered_wheel_ids[] = $wheel_id;
        }
        
        // Render wheel
        ob_start();
        include SPIN_WHEEL_PATH . 'public/templates/wheel-container.php';
        return ob_get_clean();
    }
    
    /**
     * Enqueue front assets for Auto Embed before wp_head / footer script print (shortcode runs too late if only hooked in footer).
     */
    public function maybe_enqueue_auto_embed_assets() {
        $wheel_id = $this->get_auto_embed_wheel_id_if_displayable();
        if (!$wheel_id) {
            return;
        }
        $this->enqueue_assets();
    }
    
    /**
     * Wheel ID from Auto Embed option if it should show on this request (same checks as render, without enqueue).
     *
     * @return int Wheel post ID or 0.
     */
    private function get_auto_embed_wheel_id_if_displayable() {
        if (is_admin() || is_feed() || wp_is_json_request()) {
            return 0;
        }
        $wheel_id = absint(get_option(SWP_OPTION_AUTO_EMBED_WHEEL_ID, 0));
        if (!$wheel_id) {
            return 0;
        }
        $wheel = get_post($wheel_id);
        if (!$wheel || $wheel->post_type !== 'swp_wheel' || $wheel->post_status !== 'publish') {
            return 0;
        }
        $wheel_type = get_post_meta($wheel_id, '_swp_wheel_type', true);
        $prizes     = get_post_meta($wheel_id, '_swp_prizes', true);
        if (empty($wheel_type) || empty($prizes)) {
            return 0;
        }
        $settings = get_post_meta($wheel_id, '_swp_settings', true);
        if (!is_array($settings)) {
            $settings = [];
        }
        if (!isset($settings['wheel_mode'])) {
            $wheel_mode = get_post_meta($wheel_id, '_swp_wheel_mode', true);
            $settings['wheel_mode'] = $wheel_mode ?: 'instant';
        }
        if (!$this->should_display_wheel($settings)) {
            return 0;
        }
        return $wheel_id;
    }
    
    /**
     * Output the globally selected wheel in the footer (assets enqueued earlier on wp_enqueue_scripts).
     */
    public function print_auto_embed_wheel() {
        $wheel_id = $this->get_auto_embed_wheel_id_if_displayable();
        if (!$wheel_id || in_array($wheel_id, self::$rendered_wheel_ids, true)) {
            return;
        }
        // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped -- same HTML as [spin_wheel] shortcode
        echo $this->render_shortcode_inner(['id' => (string) $wheel_id], false);
    }
    
    /**
     * Check if wheel should be displayed based on display rules
     *
     * @param array $settings Wheel settings
     * @return bool True if should display, false otherwise
     */
    private function should_display_wheel($settings) {
        // Check device targeting
        if (!$this->check_device_rules($settings)) {
            return false;
        }
        
        // Check user status rules
        if (!$this->check_user_status_rules($settings)) {
            return false;
        }
        
        // Check user role rules
        if (!$this->check_user_role_rules($settings)) {
            return false;
        }
        
        // Check page targeting rules
        if (!$this->check_page_rules($settings)) {
            return false;
        }
        
        // Check date range
        if (!$this->check_date_range($settings)) {
            return false;
        }
        
        // Check advanced conditions
        if (!$this->check_advanced_conditions($settings)) {
            return false;
        }
        
        return true;
    }
    
    /**
     * Check device rules
     *
     * @param array $settings
     * @return bool
     */
    private function check_device_rules($settings) {
        // Get device settings (default to enabled if not set)
        $device_desktop = isset($settings['device_desktop']) ? intval($settings['device_desktop']) : 1;
        $device_tablet = isset($settings['device_tablet']) ? intval($settings['device_tablet']) : 1;
        $device_mobile = isset($settings['device_mobile']) ? intval($settings['device_mobile']) : 1;
        
        // If all are disabled or all are enabled, show the wheel
        if (($device_desktop == 0 && $device_tablet == 0 && $device_mobile == 0) ||
            ($device_desktop == 1 && $device_tablet == 1 && $device_mobile == 1)) {
            return true;
        }
        
        // Detect device type
        $user_agent = isset($_SERVER['HTTP_USER_AGENT']) ? sanitize_text_field( wp_unslash( $_SERVER['HTTP_USER_AGENT'] ) ) : '';
        
        // Check for tablet first (more specific)
        $is_tablet = preg_match('/(tablet|ipad|playbook|silk)|(android(?!.*mobi))/i', $user_agent);
        
        if ($is_tablet) {
            return $device_tablet == 1;
        }
        
        // Check for mobile
        $is_mobile = wp_is_mobile() && !$is_tablet;
        
        if ($is_mobile) {
            return $device_mobile == 1;
        }
        
        // Default to desktop
        return $device_desktop == 1;
    }
    
    /**
     * Check user status rules
     *
     * @param array $settings
     * @return bool
     */
    private function check_user_status_rules($settings) {
        // If advanced conditions include user_status, skip basic user_status rules
        // to avoid conflicts (advanced conditions take precedence)
        if (!empty($settings['advanced_conditions']) && is_array($settings['advanced_conditions'])) {
            foreach ($settings['advanced_conditions'] as $condition) {
                if (!empty($condition['type']) && $condition['type'] === 'user_status') {
                    return true; // Skip basic rules, let advanced conditions handle it
                }
            }
        }
        
        if (empty($settings['user_status']) || !is_array($settings['user_status'])) {
            return true; // No restrictions
        }
        
        $user_status = $settings['user_status'];
        $is_logged_in = is_user_logged_in();
        
        if (in_array('logged_in', $user_status) && in_array('logged_out', $user_status)) {
            return true; // Both selected, show to all
        }
        
        if (in_array('logged_in', $user_status) && $is_logged_in) {
            return true;
        }
        
        if (in_array('logged_out', $user_status) && !$is_logged_in) {
            return true;
        }
        
        return false;
    }
    
    /**
     * Check user role rules
     *
     * @param array $settings
     * @return bool
     */
    private function check_user_role_rules($settings) {
        if (empty($settings['user_roles']) || !is_array($settings['user_roles'])) {
            return true; // No restrictions
        }
        
        if (!is_user_logged_in()) {
            return false; // Role restrictions require logged in user
        }
        
        $user = wp_get_current_user();
        $user_roles = (array) $user->roles;
        
        foreach ($user_roles as $role) {
            if (in_array($role, $settings['user_roles'])) {
                return true;
            }
        }
        
        return false;
    }
    
    /**
     * Check page targeting rules
     *
     * @param array $settings
     * @return bool
     */
    private function check_page_rules($settings) {
        if (empty($settings['page_targeting']) || !is_array($settings['page_targeting'])) {
            return true; // No restrictions
        }
        
        $current_page_id = get_queried_object_id();
        
        return in_array($current_page_id, array_map('intval', $settings['page_targeting']));
    }
    
    /**
     * Check date range
     *
     * @param array $settings
     * @return bool
     */
    private function check_date_range($settings) {
        $now = current_time('timestamp');
        
        // Check start date
        if (!empty($settings['start_date'])) {
            $start_timestamp = strtotime($settings['start_date']);
            if ($now < $start_timestamp) {
                return false;
            }
        }
        
        // Check end date
        if (!empty($settings['end_date'])) {
            $end_timestamp = strtotime($settings['end_date'] . ' 23:59:59');
            if ($now > $end_timestamp) {
                return false;
            }
        }
        
        return true;
    }
    
    /**
     * Check advanced conditions
     *
     * @param array $settings
     * @return bool
     */
    private function check_advanced_conditions($settings) {
        if (empty($settings['advanced_conditions']) || !is_array($settings['advanced_conditions'])) {
            return true; // No advanced conditions
        }
        
        foreach ($settings['advanced_conditions'] as $condition) {
            if (empty($condition['type']) || empty($condition['operator']) || empty($condition['value'])) {
                continue;
            }
            
            $type = $condition['type'];
            $operator = $condition['operator'];
            $value = $condition['value'];
            
            $result = false;
            
            switch ($type) {
                case 'user_status':
                    $is_logged_in = is_user_logged_in();
                    if ($operator === 'is' && $value === 'logged_in') {
                        $result = $is_logged_in;
                    } elseif ($operator === 'is' && $value === 'logged_out') {
                        $result = !$is_logged_in;
                    } elseif ($operator === 'is_not' && $value === 'logged_in') {
                        // User is NOT logged in → show wheel
                        $result = !$is_logged_in;
                    } elseif ($operator === 'is_not' && $value === 'logged_out') {
                        // User IS logged in → show wheel
                        $result = $is_logged_in;
                    }
                    break;
                    
                case 'user_role':
                    if (is_user_logged_in()) {
                        $user = wp_get_current_user();
                        $user_roles = (array) $user->roles;
                        if ($operator === 'is') {
                            $result = in_array($value, $user_roles);
                        } elseif ($operator === 'is_not') {
                            $result = !in_array($value, $user_roles);
                        }
                    } else {
                        // User is not logged in
                        if ($operator === 'is') {
                            $result = false; // Non-logged-in users don't have any role
                        } elseif ($operator === 'is_not') {
                            $result = true; // Non-logged-in users don't have the role, so "is_not" passes
                        }
                    }
                    break;
                    
                case 'page':
                    $current_page_id = get_queried_object_id();
                    if ($operator === 'is') {
                        $result = ($current_page_id == $value);
                    } elseif ($operator === 'is_not') {
                        $result = ($current_page_id != $value);
                    }
                    break;
            }
            
            if (!$result) {
                return false; // All conditions must pass
            }
        }
        
        return true;
    }
    
    /**
     * Enqueue assets
     */
    private function enqueue_assets() {
        $public_css_path = SPIN_WHEEL_PATH . 'public/css/public.css';
        $public_js_path = SPIN_WHEEL_PATH . 'public/js/public.js';
        $lucky_js_path = SPIN_WHEEL_PATH . 'public/js/lucky-canvas.umd.min.js';

        $public_css_ver = file_exists($public_css_path) ? (string) filemtime($public_css_path) : SPIN_WHEEL_VERSION;
        $public_js_ver = file_exists($public_js_path) ? (string) filemtime($public_js_path) : SPIN_WHEEL_VERSION;
        $lucky_js_ver = file_exists($lucky_js_path) ? (string) filemtime($lucky_js_path) : '1.7.27';

        wp_enqueue_style('swp-public-style', SPIN_WHEEL_URL . 'public/css/public.css', [], $public_css_ver);
        wp_enqueue_script('lucky-canvas', SPIN_WHEEL_URL . 'public/js/lucky-canvas.umd.min.js', [], $lucky_js_ver, true);
        wp_enqueue_script('swp-public-script', SPIN_WHEEL_URL . 'public/js/public.js', ['jquery', 'lucky-canvas'], $public_js_ver, true);
        
        // Get global settings for sound effects
        $settings = get_option('swp_settings', []);
        /**
         * Sound effects are a Pro feature. The free plugin emits 0 (off); Pro
         * returns the saved value when the feature is licensed and enabled.
         *
         * @param int   $enabled  Effective sound-effects flag (default 0).
         * @param array $settings Global settings.
         */
        $enable_sound_effects = (int) apply_filters('swp_effective_sound_effects', 0, $settings);
        
        wp_localize_script('swp-public-script', 'swpData', [
            'ajaxurl' => admin_url('admin-ajax.php'),
            'nonce'   => wp_create_nonce('swp_spin_nonce'),
            'pluginUrl' => SPIN_WHEEL_URL,
            'enableSoundEffects' => $enable_sound_effects,
            'i18n'    => [
                'required'                 => __('This field is required', 'spin-wheel'),
                'invalidEmail'             => __('Please enter a valid email address', 'spin-wheel'),
                'spinning'                 => __('Spinning...', 'spin-wheel'),
                'congratulations'          => __('Congratulations!', 'spin-wheel'),
                'sorry'                    => __('Sorry!', 'spin-wheel'),
                'error'                    => __('An error occurred. Please try again.', 'spin-wheel'),
                'wonAmazingPrize'         => __('You have won an amazing prize!', 'spin-wheel'),
                'yourPrize'                => __('Your Prize:', 'spin-wheel'),
                'betterLuckNextTime'      => __('Better luck next time!', 'spin-wheel'),
                'verifyOtpFirst'           => __('Please verify your email/phone with OTP before spinning.', 'spin-wheel'),
                'wheelNotInitialized'      => __('Wheel not initialized. Please refresh the page.', 'spin-wheel'),
                'prizeLabelFallback'       => __('Prize', 'spin-wheel'),
                'prizeCodeLabel'           => __('Code:', 'spin-wheel'),
                'winnerInformation'        => __('Winner Information', 'spin-wheel'),
                'participantName'          => __('Name:', 'spin-wheel'),
                'participantEmail'         => __('Email:', 'spin-wheel'),
                'participantPhone'         => __('Phone:', 'spin-wheel'),
                'fillNameEmailFirst'       => __('Please fill in your name and email first', 'spin-wheel'),
                'enterPhoneForSms'         => __('Please enter your phone number for SMS verification', 'spin-wheel'),
                'sending'                  => __('Sending...', 'spin-wheel'),
                'otpSentSuccess'           => __('Verification code sent successfully!', 'spin-wheel'),
                'otpSendFailed'            => __('Failed to send verification code.', 'spin-wheel'),
                'sendVerificationCode'     => __('Send Verification Code', 'spin-wheel'),
                'networkError'             => __('Network error. Please try again.', 'spin-wheel'),
                'enterValid6DigitCode'     => __('Please enter a valid 6-digit code', 'spin-wheel'),
                'verifying'                => __('Verifying...', 'spin-wheel'),
                'otpVerifySuccess'         => __('Verification successful!', 'spin-wheel'),
                'verified'                 => __('Verified', 'spin-wheel'),
                'invalidVerificationCode'  => __('Invalid verification code.', 'spin-wheel'),
                'verify'                   => __('Verify', 'spin-wheel'),
                /* translators: %s: countdown time remaining */
                'codeExpiresIn'            => __('Code expires in %s', 'spin-wheel'),
                'codeExpired'              => __('Code expired', 'spin-wheel'),
                'termsRequired'            => __('You must accept the terms and conditions.', 'spin-wheel'),
            ],
        ]);
    }
}
