<?php
/**
 * OAuth 2.0 API Client (Stub for Future Implementation)
 *
 * Implements PA-API authentication using OAuth 2.0 Bearer tokens.
 * Currently a stub - will be fully implemented when Amazon activates OAuth.
 */

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

require_once __DIR__ . '/interface-api-client.php';

class PSFA_OAuth_Client implements PSFA_API_Client_Interface {

    /**
     * OAuth client ID
     *
     * @var string
     */
    private $client_id;

    /**
     * OAuth client secret
     *
     * @var string
     */
    private $client_secret;

    /**
     * Associate tag
     *
     * @var string
     */
    private $associate_tag;

    /**
     * Cached access token
     *
     * @var string|null
     */
    private $access_token = null;

    /**
     * Token expiry timestamp
     *
     * @var int
     */
    private $token_expires = 0;

    /**
     * Credential version for Authorization header
     *
     * @var string
     */
    private $credential_version;

    /**
     * Marketplace domain for x-marketplace header
     *
     * @var string
     */
    private $marketplace;

    /**
     * Auth region for Cognito endpoint
     *
     * @var string
     */
    private $auth_region;

    /**
     * Creators API endpoint
     */
    const API_ENDPOINT = 'https://creatorsapi.amazon';

    /**
     * Constructor
     */
    public function __construct() {
        $this->client_id = get_option('psfa_oauth_client_id', '');
        $this->client_secret = get_option('psfa_oauth_client_secret', '');
        $this->associate_tag = get_option('psfa_associate_tag', '');
        $this->credential_version = get_option('psfa_oauth_credential_version', '');
        $this->marketplace = get_option('psfa_marketplace', 'www.amazon.com');
        $this->auth_region = get_option('psfa_oauth_auth_region', 'us-east-1');
        $this->access_token = get_option('psfa_oauth_access_token', '');
        $this->token_expires = (int) get_option('psfa_oauth_token_expires', 0);
    }

    /**
     * Execute a SearchItems request
     *
     * @param array $payload SearchItems payload (PA-API v5 format, will be converted)
     * @return array API response or error array
     */
    public function search_items(array $payload): array {
        $token = $this->get_access_token();
        if (is_wp_error($token)) {
            return ['error' => $token->get_error_message()];
        }

        // Convert PA-API v5 payload to Creators API format (camelCase)
        $creators_payload = $this->convert_to_creators_format($payload);

        return $this->execute_request('/catalog/v1/searchItems', $creators_payload, $token);
    }

    /**
     * Convert PA-API v5 payload to Creators API format
     *
     * @param array $payload PA-API v5 format payload
     * @return array Creators API format payload
     */
    private function convert_to_creators_format(array $payload): array {
        require_once __DIR__ . '/payload.php';

        $creators_payload = [
            'keywords' => $payload['Keywords'] ?? '',
            'partnerTag' => $payload['PartnerTag'] ?? $this->associate_tag,
            'marketplace' => $this->marketplace,
            'resources' => psfa_get_creators_api_resources(),
        ];

        // Optional fields
        if (!empty($payload['SearchIndex']) && $payload['SearchIndex'] !== 'All') {
            $creators_payload['searchIndex'] = $payload['SearchIndex'];
        }
        if (!empty($payload['ItemPage']) && $payload['ItemPage'] > 1) {
            $creators_payload['itemPage'] = $payload['ItemPage'];
        }
        if (!empty($payload['ItemCount'])) {
            $creators_payload['itemCount'] = $payload['ItemCount'];
        }
        if (!empty($payload['Brand'])) {
            $creators_payload['brand'] = $payload['Brand'];
        }
        if (!empty($payload['SortBy'])) {
            // Sort values stay the same (e.g., "Price:LowToHigh"), only parameter name is camelCase
            $creators_payload['sortBy'] = $payload['SortBy'];
        }
        // Creators API only accepts 'New' and 'Any' for condition.
        // Other values (Used, Refurbished, Collectible) are handled by client-side filtering
        // in psfa_filter_products_by_condition() - see result-processor.php.
        if (!empty($payload['Condition']) && in_array($payload['Condition'], array('New', 'Any'), true)) {
            $creators_payload['condition'] = $payload['Condition'];
        }
        if (!empty($payload['Merchant'])) {
            $creators_payload['merchant'] = $payload['Merchant'];
        }
        if (!empty($payload['MinReviewsRating'])) {
            $creators_payload['minReviewsRating'] = $payload['MinReviewsRating'];
        }
        if (!empty($payload['MinSavingPercent'])) {
            $creators_payload['minSavingPercent'] = $payload['MinSavingPercent'];
        }
        if (!empty($payload['Availability'])) {
            $creators_payload['availability'] = $payload['Availability'];
        }
        // Creators API supports minPrice/maxPrice (in lowest currency denomination, e.g., cents)
        if (!empty($payload['MinPrice'])) {
            $creators_payload['minPrice'] = $payload['MinPrice'];
        }
        if (!empty($payload['MaxPrice'])) {
            $creators_payload['maxPrice'] = $payload['MaxPrice'];
        }
        // DeliveryFlags for Prime filtering
        if (!empty($payload['DeliveryFlags'])) {
            $creators_payload['deliveryFlags'] = $payload['DeliveryFlags'];
        }

        return $creators_payload;
    }

    /**
     * Execute a GetItems request
     *
     * @param array $asins List of ASINs
     * @param array $resources Resources to request (ignored, uses Creators API resources)
     * @return array API response or error array
     */
    public function get_items(array $asins, array $resources): array {
        $token = $this->get_access_token();
        if (is_wp_error($token)) {
            return ['error' => $token->get_error_message()];
        }

        require_once __DIR__ . '/payload.php';

        // Creators API format (camelCase) - use GetItems-specific resources
        $payload = [
            'itemIds' => $asins,
            'partnerTag' => $this->associate_tag,
            'marketplace' => $this->marketplace,
            'resources' => psfa_get_creators_api_getitems_resources(),
        ];

        return $this->execute_request('/catalog/v1/getItems', $payload, $token);
    }

    /**
     * Check if client is properly configured
     *
     * @return bool|WP_Error
     */
    public function is_configured() {
        if (empty($this->client_id) || empty($this->client_secret)) {
            return new WP_Error('not_configured', 'OAuth credentials not configured.');
        }
        if (empty($this->credential_version)) {
            return new WP_Error('not_configured', 'Credential version not configured.');
        }
        if (empty($this->associate_tag)) {
            return new WP_Error('not_configured', 'Associate tag not configured.');
        }
        return true;
    }

    /**
     * Get client type identifier
     *
     * @return string
     */
    public function get_type(): string {
        return 'oauth';
    }

    /**
     * Get associate tag
     *
     * @return string
     */
    public function get_associate_tag(): string {
        return $this->associate_tag;
    }

    /**
     * Get valid access token (refresh if expired)
     *
     * @return string|WP_Error Access token or error
     */
    private function get_access_token() {
        // Check if we have a valid cached token
        if (!empty($this->access_token) && $this->token_expires > time() + 60) {
            return $this->access_token;
        }

        // Request new token from Amazon Cognito
        $token_url = "https://creatorsapi.auth.{$this->auth_region}.amazoncognito.com/oauth2/token";
        $basic_auth = base64_encode($this->client_id . ':' . $this->client_secret);

        $response = wp_remote_post($token_url, [
            'headers' => [
                'Content-Type' => 'application/x-www-form-urlencoded',
                'Authorization' => 'Basic ' . $basic_auth,
            ],
            'body' => 'grant_type=client_credentials&scope=creatorsapi/default',
            'timeout' => 30,
        ]);

        if (is_wp_error($response)) {
            return $response;
        }

        $code = wp_remote_retrieve_response_code($response);
        $body = json_decode(wp_remote_retrieve_body($response), true);

        if ($code !== 200 || !isset($body['access_token'])) {
            $error_msg = $body['error_description'] ?? $body['error'] ?? 'Token request failed';
            return new WP_Error('token_error', $error_msg);
        }

        // Cache the token
        $this->access_token = $body['access_token'];
        $this->token_expires = time() + ($body['expires_in'] ?? 3600);

        update_option('psfa_oauth_access_token', $this->access_token);
        update_option('psfa_oauth_token_expires', $this->token_expires);

        return $this->access_token;
    }

    /**
     * Execute API request with Bearer token
     *
     * @param string $uri API endpoint URI
     * @param array $payload Request payload
     * @param string $token Access token
     * @return array API response or error array
     */
    private function execute_request(string $uri, array $payload, string $token): array {
        $url = self::API_ENDPOINT . $uri;

        $response = wp_remote_post($url, [
            'headers' => [
                'Authorization' => 'Bearer ' . $token . ', Version ' . $this->credential_version,
                'Content-Type' => 'application/json',
                'x-marketplace' => $this->marketplace,
            ],
            'body' => wp_json_encode($payload),
            'timeout' => 15,
        ]);

        if (is_wp_error($response)) {
            return ['error' => 'HTTP Error: ' . $response->get_error_message()];
        }

        $code = wp_remote_retrieve_response_code($response);
        $body = wp_remote_retrieve_body($response);
        $decoded = json_decode($body, true);

        if ($code === 404) {
            // Creators API returns 404 when no results match the query
            return ['SearchResult' => ['Items' => [], 'TotalResultCount' => 0]];
        }

        if ($code !== 200) {
            $error_msg = 'HTTP Error: ' . $code;
            if (isset($decoded['Errors'])) {
                $error_msg .= ' - ' . wp_json_encode($decoded['Errors']);
            } elseif (isset($decoded['message'])) {
                $error_msg .= ' - ' . $decoded['message'];
            } elseif (!empty($body)) {
                $error_msg .= ' - ' . substr($body, 0, 200);
            }
            return ['error' => $error_msg, 'http_code' => $code];
        }

        if (isset($decoded['Errors'])) {
            return ['error' => 'API Error', 'details' => $decoded['Errors']];
        }

        // Normalize Creators API response (camelCase) to PA-API v5 format (PascalCase)
        return $this->normalize_response($decoded);
    }

    /**
     * Normalize Creators API response to PA-API v5 format
     * Converts camelCase keys to PascalCase for compatibility
     *
     * @param array $response Creators API response
     * @return array Normalized response
     */
    private function normalize_response(array $response): array {
        // Convert searchResult to SearchResult
        if (isset($response['searchResult'])) {
            $response['SearchResult'] = $this->normalize_search_result($response['searchResult']);
            unset($response['searchResult']);
        }
        
        // Convert itemsResult to ItemsResult (for GetItems)
        if (isset($response['itemsResult'])) {
            $response['ItemsResult'] = $this->normalize_items_result($response['itemsResult']);
            unset($response['itemsResult']);
        }
        
        return $response;
    }

    /**
     * Normalize searchResult structure
     */
    private function normalize_search_result(array $result): array {
        $normalized = [];
        
        if (isset($result['items'])) {
            $normalized['Items'] = array_map([$this, 'normalize_item'], $result['items']);
        }
        
        if (isset($result['totalResultCount'])) {
            $normalized['TotalResultCount'] = $result['totalResultCount'];
        }
        
        if (isset($result['searchRefinements'])) {
            $normalized['SearchRefinements'] = $this->normalize_keys_recursive($result['searchRefinements']);
        }
        
        return $normalized;
    }

    /**
     * Normalize itemsResult structure (for GetItems)
     */
    private function normalize_items_result(array $result): array {
        $normalized = [];
        
        if (isset($result['items'])) {
            $normalized['Items'] = array_map([$this, 'normalize_item'], $result['items']);
        }
        
        return $normalized;
    }

    /**
     * Normalize a single item
     */
    private function normalize_item(array $item): array {
        $normalized = [];
        
        // ASIN
        if (isset($item['asin'])) {
            $normalized['ASIN'] = $item['asin'];
        }
        
        // DetailPageURL
        if (isset($item['detailPageURL'])) {
            $normalized['DetailPageURL'] = $item['detailPageURL'];
        }
        
        // Images
        if (isset($item['images'])) {
            $normalized['Images'] = $this->normalize_keys_recursive($item['images']);
        }
        
        // ItemInfo
        if (isset($item['itemInfo'])) {
            $normalized['ItemInfo'] = $this->normalize_keys_recursive($item['itemInfo']);
        }
        
        // OffersV2 -> Offers compatibility
        if (isset($item['offersV2'])) {
            $normalized['OffersV2'] = $this->normalize_keys_recursive($item['offersV2']);
        }
        
        // BrowseNodeInfo
        if (isset($item['browseNodeInfo'])) {
            $normalized['BrowseNodeInfo'] = $this->normalize_keys_recursive($item['browseNodeInfo']);
        }
        
        // CustomerReviews
        if (isset($item['customerReviews'])) {
            $normalized['CustomerReviews'] = $this->normalize_keys_recursive($item['customerReviews']);
        }
        
        // ParentASIN
        if (isset($item['parentASIN'])) {
            $normalized['ParentASIN'] = $item['parentASIN'];
        }
        
        return $normalized;
    }

    /**
     * Recursively convert camelCase keys to PascalCase
     */
    private function normalize_keys_recursive($data) {
        if (!is_array($data)) {
            return $data;
        }
        
        // Special key mappings for exact matches
        $key_map = [
            'url' => 'URL',
            'asin' => 'ASIN',
            'upc' => 'UPC',
            'ean' => 'EAN',
            'isbn' => 'ISBN',
        ];
        
        $normalized = [];
        foreach ($data as $key => $value) {
            // Check for special mappings first
            $lowerKey = strtolower($key);
            if (isset($key_map[$lowerKey])) {
                $newKey = $key_map[$lowerKey];
            } else {
                // Convert camelCase to PascalCase
                $newKey = ucfirst($key);
            }
            $normalized[$newKey] = $this->normalize_keys_recursive($value);
        }
        
        return $normalized;
    }

    /**
     * Clear cached token (for testing or forced refresh)
     */
    public function clear_token(): void {
        $this->access_token = null;
        $this->token_expires = 0;
        delete_option('psfa_oauth_access_token');
        delete_option('psfa_oauth_token_expires');
    }
}
