<?php
if (!defined('ABSPATH'))
    exit;

class Dori_Chatbot_Public_API
{
    public static function init()
    {
        add_action('rest_api_init', array(__CLASS__, 'register_routes'));
        add_filter('rest_authentication_errors', array(__CLASS__, 'bypass_authentication_for_public_endpoints'), 1);
    }

    public static function bypass_authentication_for_public_endpoints($result)
    {
        if (!empty($result)) {
            return $result;
        }

        $request_uri = isset($_SERVER['REQUEST_URI']) ? esc_url_raw(wp_unslash($_SERVER['REQUEST_URI'])) : '';

        if (empty($request_uri) || '/' !== $request_uri[0]) {
            return $result;
        }

        if (
            strpos($request_uri, '/wp-json/mori/v1/') !== false ||
            strpos($request_uri, '/mori/v1/') !== false
        ) {
            return true;
        }

        return $result;
    }

    public static function register_routes()
    {
        register_rest_route(
            'mori/v1',
            '/apply',
            array(
                'methods' => 'GET',
                'callback' => array(__CLASS__, 'handle_apply_endpoint'),
                'permission_callback' => array(__CLASS__, 'check_hmac_signature'),
                'args' => array(
                    'client_id' => array(
                        'required' => true,
                        'sanitize_callback' => 'sanitize_text_field',
                    ),
                    'timestamp' => array(
                        'required' => true,
                        'sanitize_callback' => 'sanitize_text_field',
                    ),
                    'signature' => array(
                        'required' => true,
                        'sanitize_callback' => 'sanitize_text_field',
                    ),
                    'integrate_id' => array(
                        'required' => true,
                        'sanitize_callback' => 'sanitize_text_field',
                    ),
                ),
            )
        );

        register_rest_route(
            'mori/v1',
            '/cache',
            array(
                'methods' => 'GET',
                'callback' => array(__CLASS__, 'handle_cache_endpoint'),
                'permission_callback' => array(__CLASS__, 'check_hmac_signature'),
                'args' => array(
                    'client_id' => array(
                        'required' => true,
                        'sanitize_callback' => 'sanitize_text_field',
                    ),
                    'timestamp' => array(
                        'required' => true,
                        'sanitize_callback' => 'sanitize_text_field',
                    ),
                    'signature' => array(
                        'required' => true,
                        'sanitize_callback' => 'sanitize_text_field',
                    ),
                ),
            )
        );

        register_rest_route(
            'mori/v1',
            '/diagnose',
            array(
                'methods' => 'GET',
                'callback' => array(__CLASS__, 'handle_diagnose_endpoint'),
                'permission_callback' => array(__CLASS__, 'check_hmac_signature'),
                'args' => array(
                    'client_id' => array(
                        'required' => true,
                        'sanitize_callback' => 'sanitize_text_field',
                    ),
                    'timestamp' => array(
                        'required' => true,
                        'sanitize_callback' => 'sanitize_text_field',
                    ),
                    'signature' => array(
                        'required' => true,
                        'sanitize_callback' => 'sanitize_text_field',
                    ),
                ),
            )
        );
    }

    public static function check_hmac_signature(WP_REST_Request $request)
    {
        $client_id = $request->get_param('client_id');
        $timestamp = $request->get_param('timestamp');
        $signature = $request->get_param('signature');

        $route = $request->get_route();

        $timestamp_check = self::verify_request_timestamp($timestamp);
        if (is_wp_error($timestamp_check)) {
            return self::handle_failed_auth_attempt($route, $timestamp_check);
        }

        $stored_client_id = get_option('dori-chatbot-client-id', '');
        $stored_client_secret = get_option('dori-chatbot-client-secret', '');

        if (empty($stored_client_id) || empty($stored_client_secret)) {
            if ($route === '/mori/v1/apply') {
                return true;
            }

            return self::handle_failed_auth_attempt($route, new WP_Error(
                'credentials_not_configured',
                'Store credentials are not configured yet',
                array('status' => 403)
            ));
        }

        if (!hash_equals($stored_client_id, $client_id)) {
            return self::handle_failed_auth_attempt($route, new WP_Error(
                'invalid_client_id',
                'Invalid client ID',
                array('status' => 403)
            ));
        }

        $params = $request->get_query_params();
        unset($params['signature']);
        ksort($params);
        $query_string = http_build_query($params);

        $request_method = strtoupper($request->get_method());
        $to_sign = "{$request_method}\n{$query_string}\n{$timestamp}";
        $expected_signature = hash_hmac('sha256', $to_sign, $stored_client_secret);

        if (!hash_equals($expected_signature, $signature)) {
            return self::handle_failed_auth_attempt($route, new WP_Error(
                'invalid_signature',
                'Invalid request signature',
                array('status' => 403)
            ));
        }

        $rate_limit_check = self::enforce_rate_limit($route);
        if (is_wp_error($rate_limit_check)) {
            return $rate_limit_check;
        }

        return true;
    }

    private static function handle_failed_auth_attempt($route, WP_Error $error)
    {
        $rate_limit_check = self::enforce_rate_limit($route);
        if (is_wp_error($rate_limit_check)) {
            return $rate_limit_check;
        }

        return $error;
    }

    private static function enforce_rate_limit($route)
    {
        $ip_address = self::get_request_ip();
        $config = self::get_rate_limit_config();

        $window_seconds = $config['window'];
        $limit = $config['limit'];
        $bucket = (int) floor(time() / $window_seconds);

        $rate_key_source = 'auth|' . $route . '|' . $ip_address . '|' . $bucket;
        $rate_key = 'dori_chatbot_rl_' . md5($rate_key_source);

        return self::increment_rate_limit_bucket($rate_key, $limit, $window_seconds);
    }

    private static function increment_rate_limit_bucket($rate_key, $limit, $window_seconds)
    {
        $count = (int) get_transient($rate_key);

        if ($count >= $limit) {
            return new WP_Error(
                'rate_limited',
                'Too many requests. Please retry later.',
                array(
                    'status' => 429,
                    'retry_after' => $window_seconds,
                )
            );
        }

        set_transient($rate_key, $count + 1, $window_seconds + 5);

        return true;
    }

    private static function get_rate_limit_config()
    {
        return array('limit' => 3, 'window' => 60);
    }

    private static function get_request_ip()
    {
        if (!empty($_SERVER['REMOTE_ADDR'])) {
            $candidate_ip = sanitize_text_field(wp_unslash($_SERVER['REMOTE_ADDR']));
            if (filter_var($candidate_ip, FILTER_VALIDATE_IP) !== false) {
                return $candidate_ip;
            }
        }

        return 'unknown';
    }

    public static function verify_request_timestamp($timestamp)
    {
        if (empty($timestamp) || !is_numeric($timestamp)) {
            return new WP_Error(
                'invalid_timestamp',
                'Invalid or missing timestamp',
                array('status' => 400)
            );
        }

        $current_time = time();
        $time_difference = abs($current_time - intval($timestamp));
        $max_allowed_difference = 300;

        if ($time_difference > $max_allowed_difference) {
            return new WP_Error(
                'timestamp_expired',
                'Request timestamp expired. Please retry with current timestamp.',
                array('status' => 403)
            );
        }

        return true;
    }

    private static function clear_wordpress_caches()
    {
        $cleared_caches = array();

        if (function_exists('wp_cache_flush')) {
            $result = wp_cache_flush();
            if ($result !== false) {
                $cleared_caches[] = 'wp_object_cache';
            }
        }

        if (function_exists('rocket_clean_domain')) {
            rocket_clean_domain();
            $cleared_caches[] = 'wp_rocket';
        }

        if (function_exists('w3tc_flush_all')) {
            w3tc_flush_all();
            $cleared_caches[] = 'w3tc';
        }

        if (function_exists('wp_cache_clear_cache')) {
            wp_cache_clear_cache();
            $cleared_caches[] = 'wp_super_cache';
        }

        if (function_exists('litespeed_purge_all')) {
            $result = litespeed_purge_all();
            if ($result) {
                $cleared_caches[] = 'litespeed';
            }
        }

        return $cleared_caches;
    }

    public static function handle_cache_endpoint(WP_REST_Request $request)
    {
        try {
            try {
                Dori_Chatbot_Cache_Manager::clear_all_caches();
                $plugin_caches_cleared = true;
            } catch (Exception $e) {
                $plugin_caches_cleared = false;
            }

            try {
                $cleared_caches = self::clear_wordpress_caches();
                $wp_caches_cleared = !empty($cleared_caches);
            } catch (Exception $e) {
                $wp_caches_cleared = false;
                $cleared_caches = array();
            }

            return new WP_REST_Response(
                array(
                    'success' => true,
                    'message' => 'Cache clearing completed',
                    'plugin_caches_cleared' => $plugin_caches_cleared,
                    'wordpress_caches_cleared' => $wp_caches_cleared,
                    'cleared_cache_types' => $cleared_caches,
                    'timestamp' => current_time('mysql'),
                ),
                200
            );
        } catch (Exception $e) {
            return new WP_Error(
                'cache_clear_failed',
                'Failed to clear caches: ' . $e->getMessage(),
                array('status' => 500)
            );
        }
    }

    public static function handle_apply_endpoint(WP_REST_Request $request)
    {
        try {
            if (!class_exists('WooCommerce')) {
                return new WP_Error(
                    'woocommerce_required',
                    'WooCommerce is not installed or activated',
                    array('status' => 400)
                );
            }

            $integrate_id = $request->get_param('integrate_id');

            if (empty($integrate_id)) {
                throw new Exception('شناسه ادغام الزامی است');
            }

            $connection_result = Dori_Chatbot_Settings_Service::connect_store($integrate_id);

            return new WP_REST_Response(
                array(
                    'success' => true,
                    'code' => 'connection_success',
                    'sharing_id' => $connection_result['sharing_id'],
                    'connection_verified' => $connection_result['connection_verified'],
                    'timestamp' => current_time('mysql'),
                ),
                200
            );
        } catch (Exception $e) {
            return new WP_Error(
                'apply_failed',
                'Failed to apply connection: ' . $e->getMessage(),
                array('status' => 500)
            );
        }
    }

    public static function handle_diagnose_endpoint(WP_REST_Request $request)
    {
        $execution_limit = 30;

        @set_time_limit($execution_limit);

        try {
            $diagnostics = array();

            $diagnostics['plugin_configuration'] = Dori_Chatbot_Diagnostic_Utils::check_plugin_configuration();
            $diagnostics['woocommerce_integration'] = Dori_Chatbot_Diagnostic_Utils::check_woocommerce_integration();
            $diagnostics['frontend_injection'] = Dori_Chatbot_Diagnostic_Utils::check_frontend_injection();
            $diagnostics['product_detection'] = Dori_Chatbot_Diagnostic_Utils::check_product_detection();
            $diagnostics['cache_performance'] = Dori_Chatbot_Diagnostic_Utils::check_cache_performance();
            $diagnostics['cdn_network'] = Dori_Chatbot_Diagnostic_Utils::check_cdn_network();
            $diagnostics['endpoint_reachability'] = Dori_Chatbot_Diagnostic_Utils::check_endpoint_reachability();
            $diagnostics['javascript_environment'] = Dori_Chatbot_Diagnostic_Utils::check_javascript_environment();
            $diagnostics['widget_config_simulation'] = Dori_Chatbot_Diagnostic_Utils::simulate_widget_config();

            $overall_status = Dori_Chatbot_Diagnostic_Utils::determine_overall_status($diagnostics);
            $recommendations = Dori_Chatbot_Diagnostic_Utils::generate_recommendations($diagnostics);

            return new WP_REST_Response(
                array(
                    'success' => true,
                    'timestamp' => current_time('mysql'),
                    'overall_status' => $overall_status,
                    'context' => 'REST API diagnostic request',
                    'widget_requirements' => array(
                        'required_for_display' => array('sharing_id'),
                        'required_for_woocommerce_features' => array('api_keys', 'store_connection'),
                        'optional' => array('session')
                    ),
                    'diagnostics' => $diagnostics,
                    'recommendations' => $recommendations,
                ),
                200
            );
        } catch (Exception $e) {
            return new WP_Error(
                'diagnose_failed',
                'Failed to run diagnostics: ' . $e->getMessage(),
                array('status' => 500)
            );
        }
    }
}
