<?php

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

class AIEO_MOI_Provider_Wolt implements AIEO_MOI_Provider {

    const DEFAULT_BASE = 'https://pos-integration-service.wolt.com';
    const TOKEN_URL    = 'https://integrations-authentication-service.wolt.com/oauth2/token';

    
    private $webhook_vendor = null;

    public function slug()  { return 'wolt'; }
    public function label() { return 'Wolt'; }

    public function is_polling() { return false; }

    public function info_text() {
        return '<strong>' . esc_html__('Wolt POS Integration API', 'ai-eshop-optimizer') . '</strong><br>'
             . esc_html__('Delivery: Webhook (push). Give Wolt the webhook URL below + a shared secret (≥128-bit) and paste the same secret here — every inbound call is WOLT-SIGNATURE HMAC-verified.', 'ai-eshop-optimizer') . '<br>'
             . esc_html__('Outbound uses OAuth2 (rotating refresh token). Paste the client id/secret + the initial refresh token from the Wolt onboarding.', 'ai-eshop-optimizer');
    }

    public function credential_fields() {
        return array(
            array('name' => 'webhook_secret', 'label' => __('Webhook signing secret', 'ai-eshop-optimizer'), 'type' => 'password', 'required' => true,  'description' => __('Shared ≥128-bit secret Wolt uses to sign WOLT-SIGNATURE.', 'ai-eshop-optimizer')),
            array('name' => 'client_id',      'label' => __('OAuth client id', 'ai-eshop-optimizer'),        'type' => 'text',     'required' => false, 'description' => __('From Wolt partner onboarding (sent as HTTP Basic on the token call).', 'ai-eshop-optimizer')),
            array('name' => 'client_secret',  'label' => __('OAuth client secret', 'ai-eshop-optimizer'),    'type' => 'password', 'required' => false, 'description' => __('OAuth client secret.', 'ai-eshop-optimizer')),
            array('name' => 'refresh_token',  'label' => __('OAuth refresh token', 'ai-eshop-optimizer'),    'type' => 'password', 'required' => false, 'description' => __('Initial refresh token (single-use — auto-rotates and is persisted).', 'ai-eshop-optimizer')),
            array('name' => 'base_url',       'label' => __('API base URL', 'ai-eshop-optimizer'),           'type' => 'text',     'required' => false, 'description' => __('Defaults to the production POS Integration host; override for the dev gateway.', 'ai-eshop-optimizer')),
        );
    }

    public function validate_credentials(array $credentials) {
        return !empty($credentials['webhook_secret']);
    }

    public function verify_webhook($request, array $vendor) {
        $this->webhook_vendor = $vendor; 
        $secret = (string) ($vendor['credentials']['webhook_secret'] ?? '');
        if ($secret === '') {
            return new WP_Error('wolt_no_secret', __('Wolt webhook secret is not configured.', 'ai-eshop-optimizer'));
        }
        $sig = (string) $request->get_header('wolt-signature');
        if ($sig === '') {
            return new WP_Error('wolt_no_sig', __('Missing WOLT-SIGNATURE header.', 'ai-eshop-optimizer'));
        }
        $raw = (string) $request->get_body();
        $hex = hash_hmac('sha256', $raw, $secret);
        $b64 = base64_encode(hash_hmac('sha256', $raw, $secret, true));
        if (!hash_equals($hex, $sig) && !hash_equals($b64, $sig)) {
            return new WP_Error('wolt_bad_sig', __('WOLT-SIGNATURE mismatch.', 'ai-eshop-optimizer'));
        }
        return true;
    }

    public function parse_webhook_payload(array $body) {
        $env   = isset($body['order']) && is_array($body['order']) ? $body['order'] : array();
        $order_id = (string) ($env['id'] ?? ($body['order_id'] ?? ($body['id'] ?? '')));
        if ($order_id === '') { return array(); }

        $status_hint = (string) ($env['status'] ?? '');
        $full = null;
        if (is_array($this->webhook_vendor)) {
            $fetched = $this->get_order($this->webhook_vendor, $order_id, (string) ($env['resource_url'] ?? ''));
            if (!is_wp_error($fetched) && is_array($fetched) && !empty($fetched)) { $full = $fetched; }
        }
        if (null === $full) { $full = $env; } 

        return $this->normalise_order($full, $order_id, $status_hint);
    }

    public function accept_order(array $vendor, $remote_order_id, array $opts = array()) {
        $res = $this->put_action($vendor, $remote_order_id, 'accept');
        if (is_wp_error($res)) { return array('ok' => false, 'message' => $res->get_error_message()); }
        return array('ok' => true, 'message' => __('Wolt order accepted.', 'ai-eshop-optimizer'));
    }

    public function reject_order(array $vendor, $remote_order_id, $reason = '') {
        $res = $this->put_action($vendor, $remote_order_id, 'reject', (string) $reason);
        if (is_wp_error($res)) { return array('ok' => false, 'message' => $res->get_error_message()); }
        return array('ok' => true, 'message' => __('Wolt order rejected.', 'ai-eshop-optimizer'));
    }

    public function fetch_voucher(array $vendor, $remote_order_id) { return ''; }
    public function poll_orders(array $vendor, $since_ts) { return array(); }
    public function backfill_orders(array $vendor, $since_ts, $until_ts) { return array(); }

    

    
    private function normalise_order(array $o, $order_id, $status_hint) {
        list($first, $last) = $this->split_name((string) ($o['consumer_name'] ?? ''));
        $delivery = isset($o['delivery']) && is_array($o['delivery']) ? $o['delivery'] : array();
        $loc      = isset($delivery['location']) && is_array($delivery['location']) ? $delivery['location'] : array();
        $address = array(
            'first_name' => $first,
            'last_name'  => $last,
            'company'    => '',
            'address_1'  => (string) ($loc['street_address'] ?? ($loc['address'] ?? '')),
            'address_2'  => (string) ($loc['apartment'] ?? ''),
            'city'       => (string) ($loc['city'] ?? ''),
            'state'      => '',
            'postcode'   => (string) ($loc['post_code'] ?? ($loc['postal_code'] ?? '')),
            'country'    => (string) ($loc['country'] ?? ''),
            'email'      => '',
            'phone'      => (string) ($o['consumer_phone_number'] ?? ''),
        );

        $line_items = array();
        foreach ((array) ($o['items'] ?? array()) as $it) {
            if (!is_array($it)) { continue; }
            $title = (string) ($it['name'] ?? '');
            $opts  = $this->option_summary($it);
            if ($opts !== '') { $title .= ' (' . $opts . ')'; }
            $line_items[] = array(
                'remote_id'  => (string) ($it['external_data'] ?? ($it['sku'] ?? ($it['id'] ?? ''))),
                'qty'        => (int) ($it['count'] ?? ($it['quantity'] ?? 1)),
                'unit_price' => $this->money($it['unit_price'] ?? ($it['price'] ?? null)),
                'tax'        => 0.0,
                'title'      => $title,
            );
        }

        $status = $status_hint !== '' ? $status_hint : (string) ($o['order_status'] ?? '');
        $low    = strtolower($status);
        if (in_array($low, array('rejected', 'refunded', 'canceled', 'cancelled'), true)) {
            $event_type = 'order_cancelled';
        } elseif (in_array($low, array('received', 'created', 'acknowledged'), true)) {
            $event_type = 'new_order';
        } else {
            $event_type = 'order_updated';
        }

        $created = 0;
        if (!empty($o['created_at'])) {
            $created = is_numeric($o['created_at']) ? (int) $o['created_at'] : (int) strtotime((string) $o['created_at']);
        }

        return array(
            'event_type'      => $event_type,
            'remote_order_id' => (string) $order_id,
            'remote_code'     => (string) ($o['order_number'] ?? $order_id),
            'state'           => $status !== '' ? $status : 'unknown',
            'billing'         => $address,
            'shipping'        => $address,
            'line_items'      => $line_items,
            'totals'          => array(
                'shipping' => $this->money($delivery['fee'] ?? null),
                'tax'      => 0.0,
                'fees'     => 0.0,
                'total'    => $this->money($o['basket_price'] ?? ($o['total_price'] ?? null)),
            ),
            'courier'         => 'Wolt',
            'voucher_url'     => '',
            'tracking_codes'  => array(),
            'invoice'         => null,
            'gift_wrap'       => false,
            'raw'             => $o,
            'created_at'      => $created,
        );
    }

    
    private function money($m) {
        if (is_array($m) && isset($m['amount'])) { return round((float) $m['amount'] / 100, 2); }
        if (is_numeric($m)) { return (float) $m; }
        return 0.0;
    }

    private function option_summary(array $it) {
        $names = array();
        foreach ((array) ($it['options'] ?? array()) as $opt) {
            if (!is_array($opt)) { continue; }
            $v = (string) ($opt['value'] ?? ($opt['name'] ?? ''));
            if ($v !== '') { $names[] = $v; }
        }
        return implode(', ', $names);
    }

    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 base(array $vendor) {
        $b = (string) ($vendor['credentials']['base_url'] ?? '');
        return rtrim($b !== '' ? $b : self::DEFAULT_BASE, '/');
    }

    
    private function 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['client_id']) || empty($creds['client_secret']) || $refresh === '') {
                return new WP_Error('wolt_no_oauth', __('Wolt client id/secret + refresh token are required.', 'ai-eshop-optimizer'));
            }
            return AIEO_MOI_OAuth::token_request(
                self::TOKEN_URL,
                array('grant_type' => 'refresh_token', 'refresh_token' => $refresh),
                array('user' => (string) $creds['client_id'], 'pass' => (string) $creds['client_secret'])
            );
        });
    }

    private function get_order(array $vendor, $order_id, $resource_url) {
        $token = $this->token($vendor);
        if (is_wp_error($token)) { return $token; }
        $url = $resource_url !== '' ? $resource_url : ($this->base($vendor) . '/orders/' . rawurlencode($order_id));
        $resp = wp_remote_get($url, array(
            'timeout' => 25,
            'headers' => array('Authorization' => 'Bearer ' . $token, 'Accept' => 'application/json'),
        ));
        return $this->decode($resp);
    }

    private function put_action(array $vendor, $order_id, $action, $reason = '') {
        $token = $this->token($vendor);
        if (is_wp_error($token)) { return $token; }
        $body = array();
        if ('reject' === $action && $reason !== '') { $body['reason'] = (string) $reason; }
        $resp = wp_remote_request($this->base($vendor) . '/orders/' . rawurlencode($order_id) . '/' . $action, array(
            'method'  => 'PUT',
            'timeout' => 25,
            'headers' => array('Authorization' => 'Bearer ' . $token, 'Content-Type' => 'application/json', 'Accept' => 'application/json'),
            'body'    => !empty($body) ? wp_json_encode($body) : '{}',
        ));
        return $this->decode($resp);
    }

    private function decode($resp) {
        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['message']) ? (string) $json['message']
                
                : sprintf(__('Wolt API HTTP %d', 'ai-eshop-optimizer'), $code);
            return new WP_Error('wolt_api_error', $msg, array('status' => $code, 'body' => $raw));
        }
        return is_array($json) ? $json : array();
    }
}

AIEO_MOI_Provider_Registry::register(new AIEO_MOI_Provider_Wolt());
