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

/**
 * Lightweight Amazon PA-API v5 helper.
 * - Minimal signed POST to /paapi5/getitems
 * - Connection test without pulling live product data
 * - Per-ASIN caching via transients
 * - Weekly refresh entrypoint (called by SAA_Plugin cron)
 */
class SAA_API {

    /** @var SAA_Plugin */
    private $plugin;

    public function __construct(SAA_Plugin $plugin) {
        $this->plugin = $plugin;
    }

    /**
     * Public: test the connection with a minimal signed request.
     * Returns an array with success flag and message (instead of bool).
     */
    public function test_connection(): array {
        $opts = $this->plugin->get_options();
        if (!$this->has_creds($opts)) {
            return [
                'success' => false,
                'message' => __('Missing API credentials', 'slurpywp-saa-lang'),
            ];
        }
    
        $regionInfo = $this->region_info(strtoupper($opts['region']));
        if (!$regionInfo) {
            return [
                'success' => false,
                'message' => __('Invalid region code', 'slurpywp-saa-lang'),
            ];
        }
    
        $body = [
            'ItemIds'    => ['B07PX3W4RM'], // dummy ASIN, doesn't matter which
            'Resources'  => ['ItemInfo.Title'],
            'PartnerTag' => $opts['associate_tag'],
            'PartnerType'=> 'Associates',
            'Marketplace'=> $regionInfo['marketplace'],
        ];
    
        $response = $this->signed_post_json(
            $regionInfo['host'],
            '/paapi5/getitems',
            $regionInfo['aws_region'],
            $opts['access_key'],
            $opts['secret_key'],
            $body
        );
    
        if (empty($response['success'])) {
            return [
                'success' => false,
                'message' => sprintf(
                    /* translators: %s is the cURL error message */
                    __('cURL error: %s', 'slurpywp-saa-lang'),
                    $response['error']
                ),
            ];
        }
    
        $code = (int) $response['http_code'];
        $json = json_decode($response['body'], true);
    
        if ($code === 200) {
            // Credentials & signing are good, treat this as a success regardless of ASIN error
            return [
                'success' => true,
                'message' => __('Connection successful!', 'slurpywp-saa-lang'),
            ];
        }
    
        // Non-200 means a real connection failure
        $msg = sprintf(
            /* translators: %d is the HTTP response code */
            __('HTTP %d', 'slurpywp-saa-lang'),
            $code
        );
        if (isset($json['Errors'][0]['Message'])) {
            $msg .= ' - ' . $json['Errors'][0]['Message']; // Amazon’s own message, usually English
        }
    
        return [
            'success' => false,
            'message' => $msg,
        ];
    }

    /**
     * Public: fetch product data for an ASIN.
     */
    public function get_product_data(string $asin): array {
        $asin = trim($asin);
        if ($asin === '') return [];

        $cache_key = $this->cache_key($asin);
        $cached = get_transient($cache_key);
        if (is_array($cached)) {
            return $cached;
        }

        $opts = $this->plugin->get_options();
        if (!$this->has_creds($opts)) {
            return [];
        }

        $regionInfo = $this->region_info(strtoupper($opts['region']));
        if (!$regionInfo) return [];

        $body = [
            'ItemIds'    => [$asin],
            'Resources'  => [
                'Images.Primary.Medium',
                'ItemInfo.Title',
                'ItemInfo.ByLineInfo',
                'ItemInfo.Features',
                'Offers.Listings.Price',
                'Offers.Listings.SavingBasis',
                'Offers.Listings.MerchantInfo',
                'DetailPageURL',
            ],
            'PartnerTag'  => $opts['associate_tag'],
            'PartnerType' => 'Associates',
            'Marketplace' => $regionInfo['marketplace'],
        ];

        $response = $this->signed_post_json(
            $regionInfo['host'],
            '/paapi5/getitems',
            $regionInfo['aws_region'],
            $opts['access_key'],
            $opts['secret_key'],
            $body
        );

        if (empty($response['success']) || $response['http_code'] !== 200) {
            return [];
        }

        $json = json_decode($response['body'], true);
        if (!is_array($json)) {
            return [];
        }

        $item = $json['ItemsResult']['Items'][0] ?? null;
        if (!$item) return [];

        $title = $item['ItemInfo']['Title']['DisplayValue'] ?? '';
        $price = $item['Offers']['Listings'][0]['Price']['DisplayAmount'] ?? '';
        $image = $item['Images']['Primary']['Medium']['URL'] ?? '';
        $url   = $item['DetailPageURL'] ?? '';

        $data = [
            'asin'  => $asin,
            'title' => $title,
            'price' => $price,
            'desc'  => '',
            'img'   => $image,
            'url'   => $url,
        ];

        set_transient($cache_key, $data, DAY_IN_SECONDS * 7);
        $this->remember_cached_asin($asin);

        return $data;
    }

    /**
     * Cron entrypoint: refresh all cached ASINs.
     */
    public function refresh_cached_prices(): void {
        $opts = $this->plugin->get_options();
        if (!$this->has_creds($opts)) {
            return;
        }

        $asins = get_option('saa_cached_asins', []);
        if (!is_array($asins) || empty($asins)) {
            return;
        }

        foreach ($asins as $asin) {
            delete_transient($this->cache_key($asin));
            try {
                $this->get_product_data($asin);
            } catch (\Throwable $e) {
                error_log('[SAA] Refresh ASIN ' . $asin . ' failed: ' . $e->getMessage());
            }
        }
    }

    /* ---------------------------
     * Helpers
     * ------------------------- */

    private function has_creds(array $opts): bool {
        return !empty($opts['associate_tag']) &&
               !empty($opts['access_key']) &&
               !empty($opts['secret_key']) &&
               !empty($opts['region']);
    }

    private function cache_key(string $asin): string {
        return 'saa_api_' . strtolower(sanitize_key($asin));
    }

    private function remember_cached_asin(string $asin): void {
        $asins = get_option('saa_cached_asins', []);
        if (!is_array($asins)) $asins = [];
        $asin = strtoupper($asin);
        if (!in_array($asin, $asins, true)) {
            $asins[] = $asin;
            update_option('saa_cached_asins', $asins, false);
        }
    }

    private function region_info(string $code): ?array {
        $map = [
            'UK' => ['host' => 'webservices.amazon.co.uk', 'aws_region' => 'eu-west-1', 'marketplace' => 'www.amazon.co.uk'],
            'US' => ['host' => 'webservices.amazon.com',   'aws_region' => 'us-east-1', 'marketplace' => 'www.amazon.com'],
            'CA' => ['host' => 'webservices.amazon.ca',    'aws_region' => 'us-east-1', 'marketplace' => 'www.amazon.ca'],
            'DE' => ['host' => 'webservices.amazon.de',    'aws_region' => 'eu-west-1', 'marketplace' => 'www.amazon.de'],
            'FR' => ['host' => 'webservices.amazon.fr',    'aws_region' => 'eu-west-1', 'marketplace' => 'www.amazon.fr'],
            'IT' => ['host' => 'webservices.amazon.it',    'aws_region' => 'eu-west-1', 'marketplace' => 'www.amazon.it'],
            'ES' => ['host' => 'webservices.amazon.es',    'aws_region' => 'eu-west-1', 'marketplace' => 'www.amazon.es'],
            'JP' => ['host' => 'webservices.amazon.co.jp', 'aws_region' => 'us-west-2', 'marketplace' => 'www.amazon.co.jp'],
            'IN' => ['host' => 'webservices.amazon.in',    'aws_region' => 'eu-west-1', 'marketplace' => 'www.amazon.in'],
        ];
        return $map[$code] ?? null;
    }

    /**
     * Perform a SigV4-signed POST (JSON) to a PA-API endpoint using cURL.
     */
    private function signed_post_json(string $host, string $path, string $aws_region, string $access_key, string $secret_key, array $body): array {
        $service   = 'ProductAdvertisingAPI';
        $endpoint  = 'https://' . $host . $path;

        $amz_date  = gmdate('Ymd\THis\Z');
        $date_stamp = gmdate('Ymd');

        $payload = wp_json_encode($body, JSON_UNESCAPED_SLASHES);
        if ($payload === false) {
            return ['success' => false, 'error' => __('Failed to encode request JSON.', 'slurpywp-saa-lang')];
        }

        $content_type = 'application/json; charset=UTF-8';
        $amz_target   = 'com.amazon.paapi5.v1.ProductAdvertisingAPIv1.GetItems';

        // Canonical request
        $signed_headers = 'content-encoding;content-type;host;x-amz-date;x-amz-target';
        $canonical_headers =
            "content-encoding:amz-1.0\n" .
            "content-type:$content_type\n" .
            "host:$host\n" .
            "x-amz-date:$amz_date\n" .
            "x-amz-target:$amz_target\n";

        $payload_hash = hash('sha256', $payload);

        $canonical_request =
            "POST\n" .
            $path . "\n\n" .
            $canonical_headers . "\n" .
            $signed_headers . "\n" .
            $payload_hash;

        $algorithm = 'AWS4-HMAC-SHA256';
        $credential_scope = $date_stamp . '/' . $aws_region . '/' . $service . '/aws4_request';
        $string_to_sign =
            $algorithm . "\n" .
            $amz_date . "\n" .
            $credential_scope . "\n" .
            hash('sha256', $canonical_request);

        $kDate    = hash_hmac('sha256', $date_stamp, 'AWS4' . $secret_key, true);
        $kRegion  = hash_hmac('sha256', $aws_region, $kDate, true);
        $kService = hash_hmac('sha256', $service, $kRegion, true);
        $kSigning = hash_hmac('sha256', 'aws4_request', $kService, true);
        $signature = hash_hmac('sha256', $string_to_sign, $kSigning);

        $authorization_header = $algorithm . ' ' .
            'Credential=' . $access_key . '/' . $credential_scope . ', ' .
            'SignedHeaders=' . $signed_headers . ', ' .
            'Signature=' . $signature;

        $headers = [
            "Content-Encoding: amz-1.0",
            "Content-Type: $content_type",
            "Accept: application/json",
            "Host: $host",
            "X-Amz-Date: $amz_date",
            "X-Amz-Target: $amz_target",
            "Authorization: $authorization_header",
        ];

        // Debugging logs (still English only, not translated)
        error_log("[SAA] Payload: " . $payload);
        error_log("[SAA] Canonical request:\n" . $canonical_request);
        error_log("[SAA] String to sign:\n" . $string_to_sign);
        error_log("[SAA] Auth header: " . $authorization_header);
        error_log("[SAA] Final headers (cURL): " . print_r($headers, true));

        // cURL request
        $ch = curl_init($endpoint);
        curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
        curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
        curl_setopt($ch, CURLOPT_POST, true);
        curl_setopt($ch, CURLOPT_POSTFIELDS, $payload);
        curl_setopt($ch, CURLOPT_HEADER, true);

        //? Disable SSL verification on WAMP, enable on production
        curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
        curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false);

        $raw = curl_exec($ch);
        if ($raw === false) {
            $err = curl_error($ch);
            curl_close($ch);
            return ['success' => false, 'error' => $err];
        }

        $http_code = curl_getinfo($ch, CURLINFO_HTTP_CODE);
        $header_size = curl_getinfo($ch, CURLINFO_HEADER_SIZE);
        $response_headers = substr($raw, 0, $header_size);
        $response_body = substr($raw, $header_size);

        curl_close($ch);

        error_log("[SAA] Raw response headers:\n" . $response_headers);

        return [
            'success' => true,
            'http_code' => $http_code,
            'headers' => $response_headers,
            'body' => $response_body,
        ];
    }
}
