<?php

namespace LoftyIDX\includes\providers;

use LoftyIDX\includes\LoftyIDXHelpers;
use LoftyIDX\apis\LoftyIDXListingApi;
use LoftyIDX\includes\common\LoftyIDXCustomizationHelper;
use LoftyIDX\includes\common\LoftyIDXApiCache;
use LoftyIDX\includes\LoftyIDXRouter;

defined('ABSPATH') || exit;

class LoftyIDXProxyServiceProvider implements LoftyIDXBaseProvider
{
    protected $container = null;

    protected $count = 1;

    protected $api_url = LOFTY_API_PROXY;
    
    public function __construct($container)
    {
        $this->container = $container;
    }

    public function register()
    {
        $this->init_hooks();
    }

    public function init_hooks()
    {
        //  Handling logged in users Ajax ask
        add_action('wp_ajax_lofty_idx', [$this, 'handle_request']);

        //  Handling of non-logged in users Ajax ask
        add_action('wp_ajax_nopriv_lofty_idx', [$this, 'handle_request']);

        add_action('wp_ajax_lofty_idx_api', [$this, 'api_request_proxy']);

        add_action('wp_ajax_nopriv_lofty_idx_api', [$this, 'api_request_proxy']);

        add_action('wp_ajax_lofty_idx_customization', [$this, 'handle_customization_data']);

        add_action('lofty_idx_add_internal_routes_to_menu', [$this, 'add_internal_routes_to_menu'], 200);
    }

    public function api_request_proxy()
    {
        LoftyIDXListingApi::index();
    }

    public function handle_customization_data()
    {
        try{
            $params = LoftyIDXHelpers::get_request_param();
            $path = ltrim($params['path'], '/');
            $method = strtolower(sanitize_key(isset($_SERVER['REQUEST_METHOD']) ? $_SERVER['REQUEST_METHOD'] : 'GET'));
    
            if (empty($path)) {
                return $this->fail('Missing path parameter');
            }
            if ($method === 'get' && $path === 'get-custom-data') {
                return $this->success(LoftyIDXCustomizationHelper::getCustomData());
            }
            if ($method === 'post' && $path === 'set-custom-data') {
                if (!current_user_can('manage_options') ) {
                    return $this->fail('permission denied');
                }
                $config=$params['config'];  // stdClass
                $custom_css=$config->custom_css;
                $custom_js=$config->custom_js;
                $custom_html=$config->custom_html;

                LoftyIDXCustomizationHelper::setCustomData([
                    'css' => $custom_css,
                    'js'=> $custom_js,
                    'html'=> $custom_html
                ]);

                return $this->success(true);
            }
        } catch(\Exception $e){
            return $this->fail($e->getMessage());
        }
        wp_die();
    }

    public function handle_request()
    {
        try {
            $params = LoftyIDXHelpers::get_request_param();
            $path = $params['path'];
            $request_method = strtolower(sanitize_key($_SERVER['REQUEST_METHOD'] ?? 'GET'));

            if($request_method === 'post' && trim($path, '/') === 'token/key/check'){
                if (!current_user_can('manage_options') ) {
                    return $this->fail('permission denied');
                }
                return $this->updateApiKey($params);
            }

            $default_headers = $this->set_default_headers();

            if (empty($path)) {
                return $this->fail('Missing path parameter');
            }

            if ($request_method === 'get' && trim($path, '/') === 'update-routes'){
                do_action('lofty_idx_uninstall_rewrite_rules');
                do_action('lofty_idx_flush_rewrite_rules');
                LoftyIDXApiCache::deleteApiCacheData('admin/common/page/router');
                return $this->success(true);
            }

            if ($request_method === 'get' && trim($path, '/') === 'get-current-version') {
                global $wp_filesystem;
                if (empty($wp_filesystem)) {
                    require_once(ABSPATH . 'wp-admin/includes/file.php');
                    WP_Filesystem();
                }
                $readme_content = $wp_filesystem->get_contents(LOFTY_IDX_PATH . 'readme.txt');
                if (preg_match('/Stable tag:\s*([0-9]+\.[0-9]+\.[0-9]+)/', $readme_content, $matches)) {
                    return $this->success($matches[1]);
                }
                return $this->success(null);
            }

            // handle website logout, not wp logout
            if($request_method === 'get' && trim($path, '/') === 'lofty-logout') {
                $this->lofty_clear_cookie('lofty_idx_lead_id');
                $this->lofty_clear_cookie('lofty_idx_virtual_user_id');
                return $this->success(true);
            }

            if(str_ends_with($this->api_url, 'wp-plugin/') && str_starts_with($path, '/wp-plugin')){
                $path = ltrim(str_replace('/wp-plugin', '', $path), '/');
            }
            $path = ltrim($path, '/');
            $url = $this->api_url . $path;
            $args = array_replace_recursive([], $params);
            unset($args['path']);
            unset($args['action']);

            if ($request_method === 'get') {
                $url = add_query_arg($args, $url);
                
                // Check cache first
                $cacheData = LoftyIDXApiCache::getApiCacheData($path, 'GET', $args);
                if($cacheData !== false) {
                    // Check if it's an error response cache
                    if (isset($cacheData['is_error']) && $cacheData['is_error'] === true) {
                        return $this->fail('API temporarily unavailable');
                    }
                    // It's a valid cached response, use it
                    return $this->handle_response($cacheData);
                }
                
                // No cache, make the API call
                $response = wp_remote_get($url, [
                    'headers' => $default_headers,
                    'timeout' => 10,
                ]);
                
                if (isset($response['response']['code']) && $response['response']['code'] == 200) {
                    LoftyIDXApiCache::setApiCacheData($path, $response, 'GET', $args, 3600);
                } else {
                    // Cache the error for a short time (5 minutes) to prevent repeated API calls
                    $errorCache = ['is_error' => true, 'timestamp' => time()];
                    LoftyIDXApiCache::setApiCacheData($path, $errorCache, 'GET', $args, 300);
                }
                return $this->handle_response($response);
            } elseif ($request_method === 'post') {
                $response = wp_remote_post($url, [
                    'headers' => $default_headers, 
                    'body' => wp_json_encode($args),
                    'timeout' => 10,
                ]);
                if($path === 'admin/common/page/setting/update') {
                    LoftyIDXApiCache::deleteApiCacheData('admin/listing-search/searchCondition/init-info');
                }
                return $this->handle_response($response);
            }
            return $this->fail('Unsupported request method');
        } catch (\Exception $e) {
            return $this->fail($e->getMessage());
        }
        wp_die();
    }

    public function initLoftyNavMenu($body)
    {
        $data = json_decode($body);
        if($data->status->code === 0) {
            do_action('lofty_idx_add_internal_routes_to_menu');
        }
    }
    function add_internal_routes_to_menu()
    {
        // Check if auto-set primary menu is enabled
        $settings = get_option('lofty_idx_settings', []);
        $auto_set_primary = isset($settings['lofty_idx_auto_set_primary_menu']) ? $settings['lofty_idx_auto_set_primary_menu'] : '1'; // Default to enabled for backward compatibility
        
        // First, check if a menu exists or create one
        $menu_name = 'Lofty IDX';
        $menu_exists = wp_get_nav_menu_object($menu_name);

        $routes = LoftyIDXRouter::getRoutes();

        if (!$menu_exists) {
            $menu_id = wp_create_nav_menu($menu_name);
        } else {
            $menu_id = $menu_exists->term_id;
        }

        // Define your internal routes, or get routes from api
        $internal_routes = array(
            [
                'title' => 'Home',
                'url' => '/',
                'order' => 1
            ],
            [
                'title' => 'Featured',
                'url' => $routes['feature-listing']['url'] ?? '/feature-listing',
                'order' => 2
            ],
            [
                'title' => 'Search',
                'url' => $routes['listing']['url'] ?? '/listing',
                'order' => 3
            ],
            [
                'title' => 'Profile',
                'url' => '/profile',
                'order' => 4
            ]
        );

        // Add each route as a menu item
        foreach ($internal_routes as $route) {
            // Check if menu item already exists
            $existing_items = wp_get_nav_menu_items($menu_id);
            $item_exists = false;

            foreach ($existing_items as $existing_item) {
                if ($existing_item->type === 'custom' && $existing_item->url == home_url($route['url'])) {
                    $item_exists = true;
                    break;
                }
            }

            if (!$item_exists) {
                wp_update_nav_menu_item($menu_id, 0, [
                    'menu-item-title' => $route['title'],
                    'menu-item-url' => home_url($route['url']),
                    'menu-item-status' => 'publish',
                    'menu-item-type' => 'custom',
                    'menu-item-position' => $route['order']
                ]);
            }
        }

        // Only set this menu as primary menu if the setting is enabled
        if ($auto_set_primary === '1') {
            $locations = get_theme_mod('nav_menu_locations');
            $locations['primary-menu'] = $menu_id;
            set_theme_mod('nav_menu_locations', $locations);
        }
    }

    public function get_data($path, $args = [])
    {
        if(str_ends_with($this->api_url, 'wp-plugin/') && str_starts_with($path, '/wp-plugin')){
            $path = ltrim(str_replace('/wp-plugin', '', $path), '/');
        }
        $path = ltrim($path, '/');
        $url = $this->api_url . $path;
        $settings = get_option('lofty_idx_settings');
        $hasApiKey = is_array($settings) && !empty($settings['lofty_idx_api_key']);
        $default_headers = [];
        if ($path !== 'admin/common/page/router' || $hasApiKey) {
            $default_headers = $this->set_default_headers();
        }
        unset($args['path']);
        $url = add_query_arg($args, $url);
        
        // Check cache first
        $cachedResponse = LoftyIDXApiCache::getApiCacheData($path, 'GET', $args);
        if($cachedResponse !== false) {
            // Check if it's an error response cache
            if (isset($cachedResponse['is_error']) && $cachedResponse['is_error'] === true) {
                return false;
            }
            // It's a valid cached response, use it
            if (is_wp_error($cachedResponse) || $cachedResponse['response']['code'] != 200) {
                return false;
            }
            $body = wp_remote_retrieve_body($cachedResponse);
            return json_decode($body, true);
        }
        
        // No cache, make the API call
        $response = wp_remote_get($url, ['headers' => $default_headers, 'timeout'=> 10]);
        
        if (is_wp_error($response) || $response['response']['code'] != 200) {
            // Cache the error for a short time (5 minutes) to prevent repeated API calls
            $errorCache = ['is_error' => true, 'timestamp' => time()];
            LoftyIDXApiCache::setApiCacheData($path, $errorCache, 'GET', $args, 60);
            return false;
        }
        if ($hasApiKey) {
            LoftyIDXApiCache::setApiCacheData($path, $response, 'GET', $args);
        }
        $body = wp_remote_retrieve_body($response);
        return json_decode($body, true);
    }


    public function post_data($path, $params)
    {
        if(str_ends_with($this->api_url, 'wp-plugin/') && str_starts_with($path, '/wp-plugin')){
            $path = ltrim(str_replace('/wp-plugin', '', $path), '/');
        }
        $path = ltrim($path, '/');
        $url = $this->api_url . $path;
        unset($params['path']);
        unset($params['action']);
        $default_headers = $this->set_default_headers();
        $response = wp_remote_post($url, [
            'headers' => $default_headers,
            'timeout'=> 10,
            'body'=> wp_json_encode($params)
        ]);
        if (is_wp_error($response) || $response['response']['code'] != 200) {
            return false;
        }
        $body = wp_remote_retrieve_body($response);
        return json_decode($body, true);
    }

    public function updateApiKey($params)
    {
        $url = $this->api_url . 'token/key/check';
        $response = wp_remote_post($url, [
            'headers' => ['Content-Type' => 'application/json'],
            'timeout'=> 10,
            'body'=> wp_json_encode($params)
        ]);
        $this->initLoftyNavMenu($response['body']);
        do_action('lofty_idx_uninstall_rewrite_rules');
        do_action('lofty_idx_flush_rewrite_rules');
        LoftyIDXApiCache::deleteApiCacheData('admin/common/page/router');
        return $this->handle_response($response);
    }

    public function set_default_headers()
    {
        $params = LoftyIDXHelpers::get_request_param();
        $settings = get_option('lofty_idx_settings');

        if (empty($settings) || !isset($settings['lofty_idx_api_key'])) {
            return $this->fail('please set the API key in the settings first');
        }
        $secret = $settings['lofty_idx_api_key'];
        $default_headers = [
          'Content-Type' => 'application/json',
          'Accept' => 'application/json',
          'wpKey' => $this->make_signature($secret),
          'referrerUrl' => $this->make_signature(LoftyIDXHelpers::get_current_url()),
        ];


        if (
            isset($params['complianceCheck']) &&
            $params['complianceCheck'] === true &&
            isset($params['mlsOrgId']) && (
            $params['lofty_page'] == 'listing' ||
            $params['lofty_page'] == 'sold-listing' ||
            $params['pageKey'] == 'sold_listing' ||
            $params['pageKey'] == 'search'
            )
        ) {
            $default_headers['Including-Inactive-Mls'] = true;
        }
        
        $headers = $this->get_all_headers();
        if (!isset($default_headers['Including-Inactive-Mls'])) {
            if (isset($headers['including-inactive-mls'])) {
                $default_headers['Including-Inactive-Mls'] = $headers['including-inactive-mls'];
            }
        }
        if (isset($headers['trackingpagekey'])) {
            $default_headers['trackingpagekey'] = $headers['trackingpagekey'];
        }
        if(!isset($_COOKIE['lofty_idx_virtual_user_id'])) {
            $uniqueId = uniqid('wp_');
            $this->lofty_set_cookie('lofty_idx_virtual_user_id', $uniqueId);
        }
        $default_headers['loftyVirtualUserId'] = $_COOKIE['lofty_idx_virtual_user_id'] ?? '';
        $lead_id = "";
        if (isset($params['wpLead'])) {
            $lead_id = $params['wpLead'];
        } elseif (isset($_COOKIE['lofty_idx_lead_id'])) {
            $lead_id = sanitize_text_field(wp_unslash($_COOKIE['lofty_idx_lead_id']));
        }
        if (!empty($lead_id)) {
            $default_headers['wpLead'] = $this->make_signature($lead_id);
        }
     // error_log("default_headers:===============> " . json_encode($default_headers). ' '. json_encode($params). ' '. json_encode($headers));
        return $default_headers;
    }

    /**
     * Handle the response data from an external request.
     *
     * @param mixed $response The response data to handle.
     * @return mixed Processed response data.
     */
    public function handle_response($response)
    {
        $response = (array)$response;
        $code = $response['response']['code'];
        $message = $response['response']['message'];
        if (is_wp_error($response) || $code != 200) {
            return $this->fail($message);
        }
        $body = wp_remote_retrieve_body($response);
        $data = json_decode($body, false); //  Decoding the Response body For array
        if (isset($data->data) && isset($data->data->user) && !empty($data->data->user->id)) {
            $this->lofty_set_cookie('lofty_idx_lead_id', $data->data->user->id, 30 * 24 * 3600);
        }
        return wp_send_json($data, 200);
    }

    /**
     * Generates a signature using the OpenSSL extension.
     *
     * @throws \Exception If the OpenSSL extension is not loaded or if the 'key' or 'salt' is not set in the configuration.
     * @throws \Exception If encryption fails.
     * @return string The encrypted signature in hexadecimal format.
     */
    public function make_signature($data)
    {
        if (!extension_loaded('openssl')) {
            throw new \Exception('openssl extension is not loaded.');
        }

        $config = $this->container->config;
        if (!isset($config['key']) || !isset($config['salt'])) {
            throw new \Exception('Key or salt is not set in the configuration.');
        }

        $salt = LoftyIDXHelpers::generate_random_hex();

        $encrypted = openssl_encrypt($data, 'AES-128-CBC', hex2bin($config['key']), OPENSSL_RAW_DATA, hex2bin($salt));

        if (false === $encrypted) {
            $error = openssl_error_string() ?: 'Unknown error';
            throw new \Exception('Encryption failed: ' . esc_html($error));
        }

        return  LoftyIDXHelpers::generate_random_hex(2) . $salt . bin2hex($encrypted);
    }

    public function lofty_set_cookie($key, $value, $time = 10 * 365 * 24 * 3600)
    {
        if (!headers_sent()) {
            setcookie($key, $value, time() + $time, "/", parse_url(site_url(), PHP_URL_HOST));
        }
    }

    public function lofty_clear_cookie($key)
    {
        setcookie($key, '', time() - 3600, "/", parse_url(site_url(), PHP_URL_HOST));
        setcookie($key, '', time() - 3600, COOKIEPATH, COOKIE_DOMAIN); //  To maintain compatibility with previous versions.
    }

    public function respond($code, $message, $data = null)
    {
        wp_send_json([
          'status' => [
            'code' => $code,
            'message' => $message,
          ],
          'data' => $data
        ]);
        wp_die();
    }
    public function success($data, $message = 'success')
    {
        return $this->respond(200, $message, $data);
    }
    public function fail($message = 'fail', $data = null)
    {
        return $this->respond(400, $message, $data);
    }

    /**
     * 获取所有HTTP头信息，兼容低版本PHP
     * @return array
     */
    private function get_all_headers()
    {
        if (function_exists('getallheaders')) {
            return getallheaders();
        }
        
        $headers = [];
        foreach ($_SERVER as $name => $value) {
            if (substr($name, 0, 5) === 'HTTP_') {
                // 将 HTTP_HEADER_NAME 转换为 Header-Name 格式
                $header_name = str_replace(' ', '-', ucwords(strtolower(str_replace('_', ' ', substr($name, 5)))));
                $headers[$header_name] = $value;
            }
        }
        
        return $headers;
    }
}
