<?php
/**
 * Zoho CRM Authentication Handler
 *
 * Handles OAuth token management and API authentication
 *
 * @package HVAC_Community_Events
 * @subpackage Zoho_Integration
 */

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

class HVAC_Zoho_CRM_Auth {

    private $client_id;
    private $client_secret;
    private $refresh_token;
    private $redirect_uri;
    private $access_token;
    private $token_expiry;
    private $last_error = null;

    public function __construct() {
        // Load secure storage class
        if (!class_exists('HVAC_Secure_Storage')) {
            require_once plugin_dir_path(dirname(__FILE__)) . 'class-hvac-secure-storage.php';
        }

        // Load credentials from WordPress options using secure storage (encrypted)
        $this->client_id = HVAC_Secure_Storage::get_credential('hvac_zoho_client_id', '');
        $this->client_secret = HVAC_Secure_Storage::get_credential('hvac_zoho_client_secret', '');
        $this->refresh_token = HVAC_Secure_Storage::get_credential('hvac_zoho_refresh_token', '');
        $this->redirect_uri = get_site_url() . '/oauth/callback';

        // Fallback to config file if options are empty (backward compatibility)
        if (empty($this->client_id) || empty($this->client_secret)) {
            $config_file = plugin_dir_path(__FILE__) . 'zoho-config.php';
            if (file_exists($config_file)) {
                require_once $config_file;

                $this->client_id = empty($this->client_id) && defined('ZOHO_CLIENT_ID') ? ZOHO_CLIENT_ID : $this->client_id;
                $this->client_secret = empty($this->client_secret) && defined('ZOHO_CLIENT_SECRET') ? ZOHO_CLIENT_SECRET : $this->client_secret;
                $this->refresh_token = empty($this->refresh_token) && defined('ZOHO_REFRESH_TOKEN') ? ZOHO_REFRESH_TOKEN : $this->refresh_token;
                $this->redirect_uri = defined('ZOHO_REDIRECT_URI') ? ZOHO_REDIRECT_URI : $this->redirect_uri;
            }
        }

        // Load stored access token from WordPress options
        $this->load_access_token();
    }
    
    /**
     * Generate authorization URL for initial setup
     *
     * @return string Authorization URL with CSRF state parameter
     */
    public function get_authorization_url() {
        // Generate secure state parameter for CSRF protection
        $state = $this->generate_oauth_state();

        $params = array(
            'scope' => 'ZohoCRM.settings.ALL,ZohoCRM.modules.ALL,ZohoCRM.users.ALL,ZohoCRM.org.ALL,ZohoCRM.bulk.READ',
            'client_id' => $this->client_id,
            'response_type' => 'code',
            'access_type' => 'offline',
            'redirect_uri' => $this->redirect_uri,
            'prompt' => 'consent',
            'state' => $state
        );

        return 'https://accounts.zoho.com/oauth/v2/auth?' . http_build_query($params);
    }

    /**
     * Generate and store OAuth state parameter for CSRF protection
     *
     * @return string Generated state token
     */
    public function generate_oauth_state() {
        $state = wp_generate_password(32, false);
        set_transient('hvac_zoho_oauth_state', $state, 600); // 10 minute expiry
        return $state;
    }

    /**
     * Validate OAuth state parameter
     *
     * @param string $state State parameter from callback
     * @return bool True if state is valid
     */
    public function validate_oauth_state($state) {
        $stored_state = get_transient('hvac_zoho_oauth_state');

        if (empty($stored_state) || empty($state)) {
            return false;
        }

        // Use timing-safe comparison
        $valid = hash_equals($stored_state, $state);

        // Delete the state after validation (one-time use)
        delete_transient('hvac_zoho_oauth_state');

        return $valid;
    }
    
    /**
     * Exchange authorization code for tokens
     */
    public function exchange_code_for_tokens($auth_code) {
        $url = 'https://accounts.zoho.com/oauth/v2/token';
        
        $params = array(
            'grant_type' => 'authorization_code',
            'client_id' => $this->client_id,
            'client_secret' => $this->client_secret,
            'redirect_uri' => $this->redirect_uri,
            'code' => $auth_code
        );
        
        $response = wp_remote_post($url, array(
            'body' => $params,
            'headers' => array(
                'Content-Type' => 'application/x-www-form-urlencoded'
            )
        ));
        
        if (is_wp_error($response)) {
            $this->log_error('Failed to exchange code: ' . $response->get_error_message());
            return false;
        }
        
        $body = wp_remote_retrieve_body($response);
        $data = json_decode($body, true);
        
        if (isset($data['access_token']) && isset($data['refresh_token'])) {
            $this->access_token = $data['access_token'];
            $this->refresh_token = $data['refresh_token'];
            $this->token_expiry = time() + $data['expires_in'];
            
            // Save tokens
            $this->save_tokens();
            
            return true;
        }
        
        $this->log_error('Invalid token response: ' . $body);
        return false;
    }
    
    /**
     * Get valid access token (refresh if needed)
     */
    public function get_access_token() {
        // Check if token is expired or will expire soon (5 mins buffer)
        if (!$this->access_token || (time() + 300) >= $this->token_expiry) {
            $this->refresh_access_token();
        }
        
        return $this->access_token;
    }
    
    /**
     * Refresh access token using refresh token
     */
    private function refresh_access_token() {
        $url = 'https://accounts.zoho.com/oauth/v2/token';
        
        $params = array(
            'refresh_token' => $this->refresh_token,
            'client_id' => $this->client_id,
            'client_secret' => $this->client_secret,
            'grant_type' => 'refresh_token'
        );
        
        $response = wp_remote_post($url, array(
            'body' => $params,
            'headers' => array(
                'Content-Type' => 'application/x-www-form-urlencoded'
            )
        ));
        
        if (is_wp_error($response)) {
            $this->log_error('Failed to refresh token: ' . $response->get_error_message());
            return false;
        }
        
        $body = wp_remote_retrieve_body($response);
        $data = json_decode($body, true);
        
        if (isset($data['access_token'])) {
            $this->access_token = $data['access_token'];
            $this->token_expiry = time() + $data['expires_in'];
            
            $this->save_access_token();
            
            return true;
        }
        
        $this->log_error('Failed to refresh token: ' . $body);
        return false;
    }
    
    /**
     * Make authenticated API request
     */
    /**
     * Check if we are in staging mode
     * 
     * @return bool True if in staging mode
     */
    public static function is_staging_mode() {
        // 1. Allow forcing production mode via constant
        if (defined('HVAC_ZOHO_PRODUCTION_MODE') && HVAC_ZOHO_PRODUCTION_MODE) {
            return false;
        }

        // 2. Allow forcing staging mode via constant
        if (defined('HVAC_ZOHO_STAGING_MODE') && HVAC_ZOHO_STAGING_MODE) {
            return true;
        }

        // 3. Parse hostname from site URL for accurate comparison
        $site_url = get_site_url();
        $host = wp_parse_url($site_url, PHP_URL_HOST);

        if (empty($host)) {
            return true; // Can't determine host, default to staging for safety
        }

        // 4. Production: upskillhvac.com or www.upskillhvac.com
        if ($host === 'upskillhvac.com' || $host === 'www.upskillhvac.com') {
            return false;
        }

        // 5. Everything else is staging (including staging subdomains, cloudwaysapps, localhost, etc.)
        return true;
    }

    /**
     * Get details about how the mode was determined (for debugging)
     * 
     * @return array Debug information
     */
    public static function get_debug_mode_info() {
        $site_url = get_site_url();
        $host = wp_parse_url($site_url, PHP_URL_HOST);

        $info = array(
            'site_url' => $site_url,
            'parsed_host' => $host,
            'is_staging' => self::is_staging_mode(),
            'forced_production' => defined('HVAC_ZOHO_PRODUCTION_MODE') && HVAC_ZOHO_PRODUCTION_MODE,
            'forced_staging' => defined('HVAC_ZOHO_STAGING_MODE') && HVAC_ZOHO_STAGING_MODE,
            'detection_logic' => array()
        );

        // Replicate logic to show which rule matched
        if ($info['forced_production']) {
            $info['detection_logic'][] = 'Forced PRODUCTION via HVAC_ZOHO_PRODUCTION_MODE constant';
        } elseif ($info['forced_staging']) {
            $info['detection_logic'][] = 'Forced STAGING via HVAC_ZOHO_STAGING_MODE constant';
        } elseif (empty($host)) {
            $info['detection_logic'][] = 'STAGING: Could not parse hostname from URL';
        } elseif ($host === 'upskillhvac.com' || $host === 'www.upskillhvac.com') {
            $info['detection_logic'][] = 'PRODUCTION: Hostname matches upskillhvac.com';
        } else {
            $info['detection_logic'][] = 'STAGING: Hostname "' . $host . '" is not upskillhvac.com';
        }

        return $info;
    }

    /**
     * Make authenticated API request
     */
    public function make_api_request($endpoint, $method = 'GET', $data = null) {
        // Check if we're in staging mode
        $is_staging = self::is_staging_mode();
        
        // In staging mode, only allow read operations, no writes
        if ($is_staging && in_array($method, array('POST', 'PUT', 'DELETE', 'PATCH'))) {
            $this->log_debug('STAGING MODE: Blocked ' . $method . ' request to ' . $endpoint);
            return array(
                'data' => array(
                    array(
                        'code' => 'STAGING_MODE',
                        'details' => array(
                            'message' => 'Staging mode active. Write operations are disabled.'
                        ),
                        'message' => 'Blocked ' . $method . ' request to: ' . $endpoint,
                        'status' => 'skipped_staging'
                    )
                )
            );
        }
        
        // Debug logging of config status
        if (defined('ZOHO_DEBUG_MODE') && ZOHO_DEBUG_MODE) {
            $config_status = $this->get_configuration_status();
            $this->log_debug('Configuration status: ' . json_encode($config_status));
            
            if (!$config_status['client_id_exists']) {
                $this->log_error('Client ID is missing or empty');
            }
            
            if (!$config_status['client_secret_exists']) {
                $this->log_error('Client Secret is missing or empty');
            }
            
            if (!$config_status['refresh_token_exists']) {
                $this->log_error('Refresh Token is missing or empty');
            }
            
            if ($config_status['token_expired']) {
                $this->log_debug('Access token is expired, will attempt to refresh');
            }
        }
        
        $access_token = $this->get_access_token();
        
        if (!$access_token) {
            $error_message = 'No valid access token available';
            $this->log_error($error_message);
            return new WP_Error('no_token', $error_message);
        }
        
        // Update to v6 API (v2 is deprecated)
        $url = 'https://www.zohoapis.com/crm/v6' . $endpoint;
        
        // Log the request details
        $this->log_debug('Making ' . $method . ' request to: ' . $url);
        
        $args = array(
            'method' => $method,
            'headers' => array(
                'Authorization' => 'Zoho-oauthtoken ' . $access_token,
                'Content-Type' => 'application/json'
            ),
            'timeout' => 30 // Increase timeout to 30 seconds for potentially slow responses
        );
        
        if ($data && in_array($method, array('POST', 'PUT', 'PATCH'))) {
            $args['body'] = json_encode($data);
            $this->log_debug('Request payload: ' . json_encode($data));
        }
        
        // Execute the request
        $this->log_debug('Executing request to Zoho API');
        $response = wp_remote_request($url, $args);
        
        // Handle WordPress errors
        if (is_wp_error($response)) {
            $error_message = 'API request failed: ' . $response->get_error_message();
            $error_data = $response->get_error_data();
            
            $this->log_error($error_message);
            $this->log_debug('Error details: ' . json_encode($error_data));
            
            return $response;
        }
        
        // Get response code and body
        $status_code = wp_remote_retrieve_response_code($response);
        $headers = wp_remote_retrieve_headers($response);
        $body = wp_remote_retrieve_body($response);
        
        $this->log_debug('Response code: ' . $status_code);
        
        // Log headers for debugging
        if (defined('ZOHO_DEBUG_MODE') && ZOHO_DEBUG_MODE) {
            $this->log_debug('Response headers: ' . json_encode($headers->getAll()));
        }
        
        // Handle empty responses
        if (empty($body)) {
            $error_message = 'Empty response received from Zoho API';
            $this->log_error($error_message);
            return array(
                'error' => $error_message,
                'code' => $status_code,
                'details' => 'No response body received'
            );
        }
        
        // Parse the JSON response
        $data = json_decode($body, true);
        
        // Check for JSON parsing errors
        if ($data === null && json_last_error() !== JSON_ERROR_NONE) {
            $error_message = 'Invalid JSON response: ' . json_last_error_msg();
            $this->log_error($error_message);
            $this->log_debug('Raw response: ' . $body);
            
            return array(
                'error' => $error_message,
                'code' => 'JSON_PARSE_ERROR',
                'details' => 'Raw response: ' . substr($body, 0, 500),
                'request_payload' => isset($args['body']) ? $args['body'] : 'No body'
            );
        }
        
        // Log response for debugging
        if (defined('ZOHO_DEBUG_MODE') && ZOHO_DEBUG_MODE) {
            $this->log_debug('API Response: ' . $body);
        }
        
        // Check for API errors
        if ($status_code >= 400) {
            $error_message = isset($data['message']) ? $data['message'] : 'API error with status code ' . $status_code;
            $this->log_error($error_message);
            
            // Add HTTP error information to the response
            $data['http_status'] = $status_code;
            $data['error'] = $error_message;
            $data['request_payload'] = isset($args['body']) ? $args['body'] : 'No body';
            
            // Extract more detailed error information if available
            if (isset($data['code'])) {
                $this->log_debug('Error code: ' . $data['code']);
            }
            
            if (isset($data['details'])) {
                $this->log_debug('Error details: ' . json_encode($data['details']));
            }
        }
        
        return $data;
    }
    
    /**
     * Save tokens to WordPress options using secure storage
     */
    private function save_tokens() {
        HVAC_Secure_Storage::store_credential('hvac_zoho_refresh_token', $this->refresh_token);
        $this->save_access_token();
    }

    /**
     * Save access token using secure storage
     */
    private function save_access_token() {
        HVAC_Secure_Storage::store_credential('hvac_zoho_access_token', $this->access_token);
        update_option('hvac_zoho_token_expiry', $this->token_expiry);
    }

    /**
     * Load access token from WordPress options using secure storage
     */
    private function load_access_token() {
        $this->access_token = HVAC_Secure_Storage::get_credential('hvac_zoho_access_token', '');
        $this->token_expiry = get_option('hvac_zoho_token_expiry', 0);

        // Load refresh token if not set
        if (!$this->refresh_token) {
            $this->refresh_token = HVAC_Secure_Storage::get_credential('hvac_zoho_refresh_token', '');
        }
    }
    
    /**
     * Log error messages
     */
    private function log_error($message) {
        $this->last_error = $message;
        
        if (defined('ZOHO_LOG_FILE')) {
            error_log('[' . date('Y-m-d H:i:s') . '] ERROR: ' . $message . PHP_EOL, 3, ZOHO_LOG_FILE);
        }
        
        // Also log to WordPress debug log if available
        if (defined('WP_DEBUG') && WP_DEBUG && defined('WP_DEBUG_LOG') && WP_DEBUG_LOG) {
            error_log('[ZOHO CRM] ' . $message);
        }
    }
    
    /**
     * Log debug messages
     */
    public function log_debug($message) {
        // Sanitize message to remove sensitive data
        $sanitized = $this->sanitize_log_message($message);

        if (defined('ZOHO_DEBUG_MODE') && ZOHO_DEBUG_MODE && defined('ZOHO_LOG_FILE')) {
            error_log('[' . date('Y-m-d H:i:s') . '] DEBUG: ' . $sanitized . PHP_EOL, 3, ZOHO_LOG_FILE);
        }

        // Also log to WordPress debug log if available
        if (defined('ZOHO_DEBUG_MODE') && ZOHO_DEBUG_MODE && defined('WP_DEBUG') && WP_DEBUG && defined('WP_DEBUG_LOG') && WP_DEBUG_LOG) {
            error_log('[ZOHO CRM DEBUG] ' . $sanitized);
        }
    }

    /**
     * Sanitize log messages to mask sensitive credentials
     *
     * @param string $message Log message
     * @return string Sanitized message
     */
    private function sanitize_log_message($message) {
        // Mask client_id, client_secret, access_token, refresh_token patterns
        $patterns = array(
            '/(client[_-]?(id|secret)[\s:=]+)([a-zA-Z0-9._-]{10,})/i',
            '/(access[_-]?token[\s:=]+)([a-zA-Z0-9._-]{10,})/i',
            '/(refresh[_-]?token[\s:=]+)([a-zA-Z0-9._-]{10,})/i',
            '/(authorization[\s:]+)(Zoho-oauthtoken\s+[a-zA-Z0-9._-]+)/i',
            '/("(client_id|client_secret|access_token|refresh_token)"[\s:]+")[^"]+(")/i',
        );

        $replacements = array(
            '$1***MASKED***',
            '$1***MASKED***',
            '$1***MASKED***',
            '$1Zoho-oauthtoken ***MASKED***',
            '$1***MASKED***$3',
        );

        return preg_replace($patterns, $replacements, $message);
    }
    
    /**
     * Get the last error message
     *
     * @return string|null
     */
    public function get_last_error() {
        return $this->last_error;
    }
    
    /**
     * Get client ID (for debugging only)
     *
     * @return string
     */
    public function get_client_id() {
        return $this->client_id;
    }
    
    /**
     * Check if client secret exists (for debugging only)
     *
     * @return bool
     */
    public function get_client_secret() {
        return !empty($this->client_secret);
    }
    
    /**
     * Check if refresh token exists (for debugging only)
     *
     * @return bool
     */
    public function get_refresh_token() {
        return !empty($this->refresh_token);
    }
    
    /**
     * Get configuration status (for debugging)
     *
     * @return array
     */
    public function get_configuration_status() {
        return array(
            'client_id_exists' => !empty($this->client_id),
            'client_secret_exists' => !empty($this->client_secret),
            'refresh_token_exists' => !empty($this->refresh_token),
            'access_token_exists' => !empty($this->access_token),
            'token_expired' => $this->token_expiry < time(),
            'config_loaded' => file_exists(plugin_dir_path(__FILE__) . 'zoho-config.php')
        );
    }
}