<?php

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

class AIEO_MOI_Provider_Amazon implements AIEO_MOI_Provider {

    const LWA_TOKEN_URL = 'https://api.amazon.com/auth/o2/token';

    private static $hosts = array(
        'na' => 'https://sellingpartnerapi-na.amazon.com',
        'eu' => 'https://sellingpartnerapi-eu.amazon.com',
        'fe' => 'https://sellingpartnerapi-fe.amazon.com',
    );

    public function slug()  { return 'amazon'; }
    public function label() { return 'Amazon'; }

    public function info_text() {
        return '<strong>' . esc_html__('Amazon Selling Partner API (SP-API)', 'ai-eshop-optimizer') . '</strong><br>'
             . esc_html__('Auth: LWA only (no AWS keys needed since 2023). Register an SP-API app, authorise the seller, and paste the LWA client id/secret + the seller refresh token below.', 'ai-eshop-optimizer') . '<br>'
             . esc_html__('Delivery: Poll only. Buyer name/email/address are fetched via a Restricted Data Token (RDT). Region = na | eu | fe; add your marketplace id(s).', 'ai-eshop-optimizer');
    }

    public function credential_fields() {
        return array(
            array('name' => 'lwa_client_id',     'label' => __('LWA client id', 'ai-eshop-optimizer'),     'type' => 'text',     'required' => true,  'description' => __('From your SP-API app (Login with Amazon).', 'ai-eshop-optimizer')),
            array('name' => 'lwa_client_secret', 'label' => __('LWA client secret', 'ai-eshop-optimizer'), 'type' => 'password', 'required' => true,  'description' => __('LWA client secret.', 'ai-eshop-optimizer')),
            array('name' => 'refresh_token',     'label' => __('Seller refresh token', 'ai-eshop-optimizer'), 'type' => 'password', 'required' => true, 'description' => __('Long-lived refresh token from the seller’s app authorisation.', 'ai-eshop-optimizer')),
            array('name' => 'region',            'label' => __('Region (na / eu / fe)', 'ai-eshop-optimizer'), 'type' => 'text', 'required' => true,  'description' => __('na = North America, eu = Europe, fe = Far East. Picks the SP-API host.', 'ai-eshop-optimizer')),
            array('name' => 'marketplace_ids',   'label' => __('Marketplace id(s)', 'ai-eshop-optimizer'),  'type' => 'text',     'required' => true,  'description' => __('Comma-separated, e.g. UK = A1F83G8C2ARO7P, DE = A1PA6795UKMFR9.', 'ai-eshop-optimizer')),
        );
    }

    public function validate_credentials(array $credentials) {
        return !empty($credentials['lwa_client_id'])
            && !empty($credentials['lwa_client_secret'])
            && !empty($credentials['refresh_token'])
            && !empty($credentials['region'])
            && !empty($credentials['marketplace_ids']);
    }

    public function verify_webhook($request, array $vendor) {
        return new WP_Error('no_webhooks', __('Amazon SP-API is poll-only — no webhook delivery.', 'ai-eshop-optimizer'));
    }

    public function parse_webhook_payload(array $body) {
        return array();
    }

    public function accept_order(array $vendor, $remote_order_id, array $opts = array()) {
        
        
        
        return array('ok' => true, 'message' => __('Amazon orders need no acceptance — confirm shipment (carrier + tracking) when the order ships.', 'ai-eshop-optimizer'));
    }

    public function reject_order(array $vendor, $remote_order_id, $reason = '') {
        return array('ok' => false, 'message' => __('Amazon has no order-rejection API — cancellations originate on Amazon and sync back on the next poll.', 'ai-eshop-optimizer'));
    }

    public function fetch_voucher(array $vendor, $remote_order_id) {
        return ''; 
    }

    public function poll_orders(array $vendor, $since_ts) {
        $res = $this->fetch_window($vendor, (int) $since_ts, 0);
        return is_wp_error($res) ? array() : $res;
    }

    public function backfill_orders(array $vendor, $since_ts, $until_ts) {
        $res = $this->fetch_window($vendor, (int) $since_ts, (int) $until_ts);
        if (is_wp_error($res)) {
            
            throw new \RuntimeException('Amazon SP-API: ' . $res->get_error_message());
        }
        return $res;
    }

    

    private function fetch_window(array $vendor, $since_ts, $until_ts) {
        $lwa = $this->lwa_token($vendor);
        if (is_wp_error($lwa)) { return $lwa; }
        $rdt = $this->mint_rdt($vendor, $lwa);
        if (is_wp_error($rdt)) { return $rdt; }

        $markets = array_values(array_filter(array_map('trim', explode(',', (string) ($vendor['credentials']['marketplace_ids'] ?? '')))));
        if (empty($markets)) {
            return new WP_Error('amazon_no_marketplace', __('Amazon marketplace id(s) required.', 'ai-eshop-optimizer'));
        }

        $out   = array();
        $next  = '';
        $guard = 0;
        do {
            if ($next !== '') {
                $query = array('MarketplaceIds' => implode(',', $markets), 'NextToken' => $next);
            } else {
                $query = array(
                    'MarketplaceIds'   => implode(',', $markets),
                    'OrderStatuses'    => 'Unshipped,PartiallyShipped,Shipped,Canceled',
                    'LastUpdatedAfter' => gmdate('Y-m-d\TH:i:s\Z', max(0, (int) $since_ts - 120)),
                );
                if ((int) $until_ts > 0) {
                    $query['LastUpdatedBefore'] = gmdate('Y-m-d\TH:i:s\Z', (int) $until_ts);
                }
            }

            $resp = $this->api_get($vendor, '/orders/v0/orders', $query, $rdt);
            if (is_wp_error($resp)) {
                if ($next === '') { return $resp; }
                break;
            }
            $payload = isset($resp['payload']) && is_array($resp['payload']) ? $resp['payload'] : array();
            foreach ((array) ($payload['Orders'] ?? array()) as $order) {
                if (!is_array($order)) { continue; }
                if (($order['OrderStatus'] ?? '') === 'Pending') { continue; } 
                $items = $this->fetch_items($vendor, (string) ($order['AmazonOrderId'] ?? ''), $rdt);
                $out[] = $this->normalise_order($order, $items);
            }
            $next = (string) ($payload['NextToken'] ?? '');
        } while ($next !== '' && $guard++ < 50);

        return $out;
    }

    private function fetch_items(array $vendor, $order_id, $rdt) {
        if ($order_id === '') { return array(); }
        $items = array();
        $next  = '';
        $guard = 0;
        do {
            $query = $next !== '' ? array('NextToken' => $next) : array();
            $resp  = $this->api_get($vendor, '/orders/v0/orders/' . rawurlencode($order_id) . '/orderitems', $query, $rdt);
            if (is_wp_error($resp)) { break; }
            $payload = isset($resp['payload']) && is_array($resp['payload']) ? $resp['payload'] : array();
            foreach ((array) ($payload['OrderItems'] ?? array()) as $it) {
                if (is_array($it)) { $items[] = $it; }
            }
            $next = (string) ($payload['NextToken'] ?? '');
        } while ($next !== '' && $guard++ < 20);
        return $items;
    }

    
    private function normalise_order(array $o, array $items) {
        $ship  = isset($o['ShippingAddress']) && is_array($o['ShippingAddress']) ? $o['ShippingAddress'] : array();
        $buyer = isset($o['BuyerInfo']) && is_array($o['BuyerInfo']) ? $o['BuyerInfo'] : array();
        list($first, $last) = $this->split_name((string) ($ship['Name'] ?? ($buyer['BuyerName'] ?? '')));

        $address = array(
            'first_name' => $first,
            'last_name'  => $last,
            'company'    => '',
            'address_1'  => (string) ($ship['AddressLine1'] ?? ''),
            'address_2'  => trim((string) ($ship['AddressLine2'] ?? '') . ' ' . (string) ($ship['AddressLine3'] ?? '')),
            'city'       => (string) ($ship['City'] ?? ''),
            'state'      => (string) ($ship['StateOrRegion'] ?? ''),
            'postcode'   => (string) ($ship['PostalCode'] ?? ''),
            'country'    => (string) ($ship['CountryCode'] ?? ''),
            'email'      => (string) ($buyer['BuyerEmail'] ?? ''),
            'phone'      => (string) ($ship['Phone'] ?? ''),
        );

        $line_items = array();
        $tax_total  = 0.0;
        foreach ($items as $it) {
            $qty        = (int) ($it['QuantityOrdered'] ?? 1);
            $line_total = (float) ($it['ItemPrice']['Amount'] ?? 0); 
            $line_tax   = (float) ($it['ItemTax']['Amount'] ?? 0);
            $tax_total += $line_tax;
            $line_items[] = array(
                'remote_id'  => (string) ($it['SellerSKU'] ?? ($it['ASIN'] ?? '')),
                'qty'        => $qty,
                'unit_price' => $qty > 0 ? round(($line_total - $line_tax) / $qty, 4) : 0.0, 
                'tax'        => $line_tax,
                'title'      => (string) ($it['Title'] ?? ''),
            );
        }

        $status = (string) ($o['OrderStatus'] ?? '');
        $event_type = ('Canceled' === $status) ? 'order_cancelled' : ('Unshipped' === $status ? 'new_order' : 'order_updated');

        return array(
            'event_type'      => $event_type,
            'remote_order_id' => (string) ($o['AmazonOrderId'] ?? ''),
            'remote_code'     => (string) ($o['AmazonOrderId'] ?? ''),
            'state'           => $status !== '' ? $status : 'unknown',
            'billing'         => $address,
            'shipping'        => $address,
            'line_items'      => $line_items,
            'totals'          => array(
                'shipping' => 0.0,
                'tax'      => $tax_total,
                'fees'     => 0.0,
                'total'    => (float) ($o['OrderTotal']['Amount'] ?? 0),
            ),
            'courier'         => (string) ($o['ShipmentServiceLevelCategory'] ?? ''),
            'voucher_url'     => '',
            'tracking_codes'  => array(),
            'invoice'         => null,
            'gift_wrap'       => false,
            'raw'             => array('order' => $o, 'items' => $items, 'fulfillment_channel' => (string) ($o['FulfillmentChannel'] ?? '')),
            'created_at'      => !empty($o['PurchaseDate']) ? (int) strtotime((string) $o['PurchaseDate']) : 0,
        );
    }

    private function split_name($name) {
        $name = trim((string) $name);
        if ($name === '') { return array('', ''); }
        $parts = preg_split('/\s+/', $name, 2);
        return array($parts[0], isset($parts[1]) ? $parts[1] : '');
    }

    

    private function host(array $vendor) {
        $r = strtolower((string) ($vendor['credentials']['region'] ?? 'eu'));
        return isset(self::$hosts[$r]) ? self::$hosts[$r] : self::$hosts['eu'];
    }

    
    private function lwa_token(array $vendor) {
        return AIEO_MOI_OAuth::access_token($vendor, function ($oauth_state, $creds) {
            $refresh = AIEO_MOI_OAuth::refresh_token($oauth_state, $creds, 'refresh_token');
            if (empty($creds['lwa_client_id']) || empty($creds['lwa_client_secret']) || $refresh === '') {
                return new WP_Error('amazon_no_lwa', __('Amazon LWA client id/secret + seller refresh token are required.', 'ai-eshop-optimizer'));
            }
            return AIEO_MOI_OAuth::token_request(self::LWA_TOKEN_URL, array(
                'grant_type'    => 'refresh_token',
                'refresh_token' => $refresh,
                'client_id'     => (string) $creds['lwa_client_id'],
                'client_secret' => (string) $creds['lwa_client_secret'],
            ));
        });
    }

    
    private function mint_rdt(array $vendor, $lwa_token) {
        $body = array('restrictedResources' => array(
            array('method' => 'GET', 'path' => '/orders/v0/orders',                  'dataElements' => array('buyerInfo', 'shippingAddress')),
            array('method' => 'GET', 'path' => '/orders/v0/orders/{orderId}/orderitems', 'dataElements' => array('buyerInfo')),
        ));
        $resp = wp_remote_post($this->host($vendor) . '/tokens/2021-03-01/restrictedDataToken', array(
            'timeout' => 25,
            'headers' => array(
                'x-amz-access-token' => $lwa_token,
                'Content-Type'       => 'application/json',
                'Accept'             => 'application/json',
            ),
            'body'    => wp_json_encode($body),
        ));
        if (is_wp_error($resp)) { return $resp; }
        $json = json_decode((string) wp_remote_retrieve_body($resp), true);
        if (!is_array($json) || empty($json['restrictedDataToken'])) {
            $msg = is_array($json) && !empty($json['errors'][0]['message']) ? (string) $json['errors'][0]['message'] : __('Could not mint Amazon RDT.', 'ai-eshop-optimizer');
            return new WP_Error('amazon_no_rdt', $msg);
        }
        return (string) $json['restrictedDataToken'];
    }

    
    private function api_get(array $vendor, $path, array $query, $token) {
        $url = $this->host($vendor) . $path;
        if (!empty($query)) { $url = add_query_arg($query, $url); }
        $resp = wp_remote_get($url, array(
            'timeout' => 30,
            'headers' => array(
                'x-amz-access-token' => $token,
                'Accept'             => 'application/json',
            ),
        ));
        if (is_wp_error($resp)) { return $resp; }
        $code = (int) wp_remote_retrieve_response_code($resp);
        $raw  = (string) wp_remote_retrieve_body($resp);
        $json = json_decode($raw, true);
        if ($code >= 400) {
            $msg = is_array($json) && !empty($json['errors'][0]['message']) ? (string) $json['errors'][0]['message']
                
                : sprintf(__('Amazon SP-API HTTP %d', 'ai-eshop-optimizer'), $code);
            return new WP_Error('amazon_api_error', $msg, array('status' => $code, 'body' => $raw));
        }
        if (!is_array($json)) {
            return new WP_Error('amazon_bad_json', __('Non-JSON response from SP-API.', 'ai-eshop-optimizer'));
        }
        return $json;
    }
}

AIEO_MOI_Provider_Registry::register(new AIEO_MOI_Provider_Amazon());
