<?php
/**
 * LinkCentral Dynamic Rules
 *
 * Handles dynamic redirection rules for premium users.
 */
if ( ! defined( 'ABSPATH' ) ) exit; // Exit if accessed directly

class LinkCentral_Dynamic_Rules {
    private $geolocation;
    private $visitor_manager;

    public function __construct($geolocation, $visitor_manager) {
        $this->geolocation = $geolocation;
        $this->visitor_manager = $visitor_manager;
    }

    /**
     * Get the dynamic destination URL based on rules.
     */
    public function get_dynamic_destination_url($link_id, $rules) {
        if (empty($rules) || !is_array($rules)) {
            return false;
        }

        foreach ($rules as $rule) {
            if ($this->rule_matches($rule['variables'], $link_id)) {
                return $rule['destination'];
            }
        }

        return false;
    }

    /**
     * Check if a rule matches the current conditions.
     */
    private function rule_matches($variables, $link_id) {
        foreach ($variables as $variable) {

            list($type, $condition, $value) = $variable;

            switch ($type) {
                case 'country':
                    if (!$this->check_country_condition($condition, $value)) {
                        return false;
                    }
                    break;
                case 'device':
                    if (!$this->check_device_condition($condition, $value)) {
                        return false;
                    }
                    break;
                case 'operating_system':
                    if (!$this->check_operating_system_condition($condition, $value)) {
                        return false;
                    }
                    break;
                case 'date':
                    if (!$this->check_date_condition($condition, $value)) {
                        return false;
                    }
                    break;
                case 'time':
                    if (!$this->check_time_condition($condition, $value)) {
                        return false;
                    }
                    break;
                case 'cookie':
                    if (!$this->check_cookie_condition($condition, $value)) {
                        return false;
                    }
                    break;
                case 'logged_in_status':
                    if (!$this->check_logged_in_status_condition($condition, $value)) {
                        return false;
                    }
                    break;
                case 'total_clicks':
                    if (!$this->check_total_clicks_condition($condition, $value, $link_id)) {
                        return false;
                    }
                    break;
                case 'unique_clicks':
                    if (!$this->check_unique_clicks_condition($condition, $value, $link_id)) {
                        return false;
                    }
                    break;
                case 'url_parameter':
                    if (!$this->check_url_parameter_condition($condition, $value)) {
                        return false;
                    }
                    break;
            }
        }

        return true;
    }

    /**
     * Check if the country condition is met.
     */
    private function check_country_condition($condition, $value) {

        $location = $this->geolocation->get_user_location();
        $user_country = is_array($location) && isset($location['country']) ? $location['country'] : '';

        if ($condition === 'is') {
            return in_array($user_country, $value);
        } elseif ($condition === 'is not') {
            return !in_array($user_country, $value);
        }

        return false;
    }

    /**
     * Check if the device condition is met.
     */
    private function check_device_condition($condition, $value) {
        $user_agent = $this->visitor_manager->get_user_agent();
        $user_device = LinkCentral_User_Agent_Parser::get_device($user_agent);

        // Convert to lowercase to match frontend expectations (desktop, mobile, tablet)
        $user_device = strtolower($user_device);

        if ($condition === 'is') {
            return in_array($user_device, $value);
        } elseif ($condition === 'is not') {
            return !in_array($user_device, $value);
        }

        return false;
    }

    /**
     * Check if the date condition is met.
     */
    private function check_date_condition($condition, $value) {
        $current_date = current_time('Y-m-d');

        switch ($condition) {
            case 'is_before':
                return $current_date < $value;
            case 'is_after':
                return $current_date > $value;
            case 'is_on':
                return $current_date === $value;
            case 'is_between':
            case 'is_not_between':
                if (is_array($value) && count($value) === 2) {
                    $start_date = $value[0];
                    $end_date = $value[1];
                    $is_between = ($current_date >= $start_date && $current_date <= $end_date);
                    return $condition === 'is_between' ? $is_between : !$is_between;
                }
                return false;
        }

        return false;
    }

    /**
     * Check if the time condition is met.
     */
    private function check_time_condition($condition, $value) {
        $current_time = current_time('H:i');

        switch ($condition) {
            case 'is_before':
                return $current_time < $value;
            case 'is_after':
                return $current_time > $value;
            case 'is':
                return $current_time === $value;
            case 'is_between':
            case 'is_not_between':
                if (is_array($value) && count($value) === 2) {
                    $start_time = $value[0];
                    $end_time = $value[1];
                    $is_between = ($start_time <= $end_time)
                        ? ($current_time >= $start_time && $current_time <= $end_time)
                        : ($current_time >= $start_time || $current_time <= $end_time);
                    return $condition === 'is_between' ? $is_between : !$is_between;
                }
                return false;
        }

        return false;
    }

    /**
     * Check if the cookie condition is met.
     */
    private function check_cookie_condition($condition, $value) {
        if (!is_array($value) && !is_object($value)) {
            return false;
        }

        $cookie_name = isset($value['name']) ? sanitize_text_field($value['name']) : '';

        if (empty($cookie_name)) {
            return false;
        }

        $cookie_exists = isset($_COOKIE[$cookie_name]);

        switch ($condition) {
            case 'is_set':
                return $cookie_exists;
            case 'is_not_set':
                return !$cookie_exists;
            case 'has_value':
                if (!$cookie_exists) {
                    return false;
                }

                $expected_value = isset($value['value']) ? sanitize_text_field($value['value']) : '';
                $actual_value = sanitize_text_field(wp_unslash($_COOKIE[$cookie_name]));

                return $actual_value === $expected_value;
            default:
                return false;
        }
    }

    /**
     * Check if the logged_in_status condition is met.
     */
    private function check_logged_in_status_condition($condition, $value) {
        if ($condition !== 'is' || !is_array($value) || !isset($value['status'])) {
            return false;
        }

        $current_user = wp_get_current_user();
        $is_logged_in = $current_user->exists();
        $expected_status = $value['status'];

        switch ($expected_status) {
            case 'logged_out':
                return !$is_logged_in;

            case 'logged_in':
                return $is_logged_in;

            case 'logged_in_with_role':
                if (!$is_logged_in) {
                    return false;
                }

                // Check if user has any of the required roles
                if (!isset($value['roles']) || !is_array($value['roles']) || empty($value['roles'])) {
                    return false;
                }

                $user_roles = $current_user->roles;
                foreach ($value['roles'] as $required_role) {
                    if (in_array($required_role, $user_roles)) {
                        return true;
                    }
                }

                return false;

            default:
                return false;
        }
    }

    /**
     * Check if the URL parameter condition is met.
     */
    private function check_url_parameter_condition($condition, $value) {
        if (!is_array($value) && !is_object($value)) {
            return false;
        }

        $parameter_name = isset($value['name']) ? sanitize_text_field($value['name']) : '';

        if (empty($parameter_name)) {
            return false;
        }

        // Get the query string from the current request
        $query_string = '';
        if (isset($_SERVER['QUERY_STRING'])) {
            $query_string = sanitize_text_field(wp_unslash($_SERVER['QUERY_STRING']));
        }

        // Parse query parameters
        $query_params = array();
        if (!empty($query_string)) {
            parse_str($query_string, $query_params);
        }

        $parameter_exists = isset($query_params[$parameter_name]);

        switch ($condition) {
            case 'is_set':
                return $parameter_exists;
            case 'is_not_set':
                return !$parameter_exists;
            case 'has_value':
                if (!$parameter_exists) {
                    return false;
                }

                $expected_value = isset($value['value']) ? sanitize_text_field($value['value']) : '';
                $actual_value = sanitize_text_field($query_params[$parameter_name]);

                return $actual_value === $expected_value;
            default:
                return false;
        }
    }

    /**
     * Check if the total clicks condition is met.
     */
    private function check_total_clicks_condition($condition, $value, $link_id) {
        global $wpdb;

        // Get total clicks for this link
        $total_clicks = $wpdb->get_var($wpdb->prepare(
            "SELECT COUNT(*) FROM `{$wpdb->prefix}linkcentral_stats` WHERE link_id = %d",
            $link_id
        ));

        $total_clicks = $total_clicks + 1; // Add 1 to total_clicks since we're checking before recording the current click

        switch ($condition) {
            case 'is_fewer_than':
                return $total_clicks < intval($value);
            case 'is_more_than':
                return $total_clicks > intval($value);
            case 'is_every':
                // For 'every' condition, check if the current click number is divisible by the value
                return $total_clicks % intval($value) === 0;
            default:
                return false;
        }
    }

    /**
     * Check if the operating system condition is met.
     */
    private function check_operating_system_condition($condition, $value) {
        // Get user agent from visitor manager
        $user_agent = $this->visitor_manager->get_user_agent();
        $user_os = LinkCentral_User_Agent_Parser::get_operating_system($user_agent);

        // Map specific OS results to combined categories for frontend compatibility
        // Combine all Windows versions into "Windows"
        if (strpos($user_os, 'Windows') === 0) {
            $mapped_os = 'Windows';
        }
        // Combine macOS and iOS into "Apple"
        elseif ($user_os === 'macOS' || $user_os === 'iOS') {
            $mapped_os = 'Apple';
        }
        // Keep others as-is
        else {
            $mapped_os = $user_os;
        }

        if ($condition === 'is') {
            return in_array($mapped_os, $value);
        } elseif ($condition === 'is not') {
            return !in_array($mapped_os, $value);
        }

        return false;
    }

    /**
     * Check if the unique clicks condition is met.
     */
    private function check_unique_clicks_condition($condition, $value, $link_id) {
        global $wpdb;

        // Get unique clicks for this link
        $unique_clicks = $wpdb->get_var($wpdb->prepare(
            "SELECT COUNT(DISTINCT visitor_id) FROM `{$wpdb->prefix}linkcentral_stats` WHERE link_id = %d",
            $link_id
        ));

        $reporting_disabled = get_option('linkcentral_disable_reporting', false);
        if (!$reporting_disabled) {
            // Only check current visitor when reporting is enabled (to avoid setting cookies)
            $visitor_id = $this->visitor_manager->get_or_set_visitor_id();

            // Check if this visitor has clicked before
            $visitor_clicked = $wpdb->get_var($wpdb->prepare(
                "SELECT COUNT(*) FROM `{$wpdb->prefix}linkcentral_stats` WHERE link_id = %d AND visitor_id = %s",
                $link_id,
                $visitor_id
            ));

            // If this is a new visitor, add 1 to unique_clicks
            if ($visitor_clicked === '0') {
                $unique_clicks = $unique_clicks + 1;
            }
        }
        // When reporting is disabled, just use the historical unique clicks count (don't add 1)

        switch ($condition) {
            case 'is_fewer_than':
                return $unique_clicks < intval($value);
            case 'is_more_than':
                return $unique_clicks > intval($value);
            case 'is_every':
                // For 'every' condition, check if the current unique click number is divisible by the value
                return $unique_clicks % intval($value) === 0;
            default:
                return false;
        }
    }
}
