<?php

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

class AIEO_Courier_Driver_BoxNow extends AIEO_Courier_Driver_Base {

    const TOKEN_TRANSIENT = 'aieo_boxnow_token';

    public function code()  { return 'boxnow'; }
    public function label() { return 'BOX NOW'; }

    public function capabilities() {
        return array('create', 'print', 'cancel', 'track', 'shop_list');
    }

    public function settings_schema() {
        return array(
            'environment' => array(
                'type'    => 'select',
                'label'   => __('Environment', 'ai-eshop-optimizer'),
                'options' => array(
                    'production' => __('Production', 'ai-eshop-optimizer'),
                    'stage'      => __('Stage / Sandbox', 'ai-eshop-optimizer'),
                ),
            ),
            'client_id'     => array('type' => 'text', 'label' => __('OAuth Client ID', 'ai-eshop-optimizer')),
            'client_secret' => array('type' => 'password', 'label' => __('OAuth Client Secret', 'ai-eshop-optimizer')),
            'warehouse_id'  => array(
                'type'  => 'text',
                'label' => __('Origin / warehouse location ID', 'ai-eshop-optimizer'),
                'help'  => __('Your BOX NOW pickup point id (e.g. 2). Used as the delivery origin.', 'ai-eshop-optimizer'),
            ),
            'origin_contact_name'  => array('type' => 'text', 'label' => __('Origin contact name', 'ai-eshop-optimizer')),
            'origin_contact_email' => array('type' => 'text', 'label' => __('Origin contact email', 'ai-eshop-optimizer')),
            'origin_contact_phone' => array('type' => 'text', 'label' => __('Origin contact phone (+30…)', 'ai-eshop-optimizer')),
            'default_compartment'  => array(
                'type'    => 'select',
                'label'   => __('Default compartment size', 'ai-eshop-optimizer'),
                'options' => array('1' => __('Small', 'ai-eshop-optimizer'), '2' => __('Medium', 'ai-eshop-optimizer'), '3' => __('Large', 'ai-eshop-optimizer')),
            ),
            'enable_mirror' => array(
                'type'  => 'checkbox',
                'label' => __('Also mirror legacy box-now-delivery vouchers into the unified table', 'ai-eshop-optimizer'),
            ),
        );
    }

    public function tracking_url($voucher_no) {
        return AIEO_Runtime_Fulfillment_URLs::tracking_url('boxnow', (string) $voucher_no);
    }

    
    
    

    private function creds() {
        $c = $this->get_setting('client_id', '');
        $s = $this->get_setting('client_secret', '');
        return array('client_id' => (string) $c, 'client_secret' => (string) $s);
    }

    private function is_stage() {
        return $this->get_setting('environment', 'production') === 'stage';
    }

    private function api_base() {
        return $this->is_stage() ? 'https://api-stage.boxnow.gr' : 'https://api-production.boxnow.gr';
    }

    private function location_base() {
        return $this->is_stage() ? 'https://locationapi-stage.boxnow.gr' : 'https://locationapi-production.boxnow.gr';
    }

    
    private function token() {
        $cached = get_transient(self::TOKEN_TRANSIENT);
        if (is_string($cached) && $cached !== '') {
            return array('ok' => true, 'token' => $cached);
        }
        $creds = $this->creds();
        if ($creds['client_id'] === '' || $creds['client_secret'] === '') {
            return array('ok' => false, 'error' => __('BOX NOW credentials missing in settings.', 'ai-eshop-optimizer'));
        }
        $resp = wp_remote_post($this->api_base() . '/api/v1/auth-sessions', array(
            'timeout' => 30,
            'headers' => array('Content-Type' => 'application/json', 'Accept' => 'application/json'),
            'body'    => wp_json_encode(array(
                'grant_type'    => 'client_credentials',
                'client_id'     => $creds['client_id'],
                'client_secret' => $creds['client_secret'],
            )),
        ));
        if (is_wp_error($resp)) {
            return array('ok' => false, 'error' => $resp->get_error_message());
        }
        $code = (int) wp_remote_retrieve_response_code($resp);
        $data = json_decode((string) wp_remote_retrieve_body($resp), true);
        if ($code !== 200 || !is_array($data) || empty($data['access_token'])) {
            $msg = is_array($data) && !empty($data['code']) ? (string) $data['code'] : ('HTTP ' . $code);
            return array('ok' => false, 'error' => sprintf(__('BOX NOW auth failed: %s', 'ai-eshop-optimizer'), $msg));
        }
        $token   = (string) $data['access_token'];
        $expires = isset($data['expires_in']) ? max(60, (int) $data['expires_in']) : 3600;
        set_transient(self::TOKEN_TRANSIENT, $token, $expires - 60);
        return array('ok' => true, 'token' => $token);
    }

    
    private function request($method, $url, array $opts = array()) {
        $tok = $this->token();
        if (empty($tok['ok'])) { return array('ok' => false, 'error' => $tok['error']); }

        $headers = array(
            'Authorization' => 'Bearer ' . $tok['token'],
            'Accept'        => isset($opts['accept']) ? $opts['accept'] : 'application/json',
        );
        $args = array('method' => $method, 'timeout' => 40, 'headers' => $headers);
        if (isset($opts['body'])) {
            $headers['Content-Type'] = 'application/json';
            $args['headers'] = $headers;
            $args['body']    = wp_json_encode($opts['body']);
        }
        $resp = wp_remote_request($url, $args);
        if (is_wp_error($resp)) { return array('ok' => false, 'error' => $resp->get_error_message()); }
        $code = (int) wp_remote_retrieve_response_code($resp);
        $body = (string) wp_remote_retrieve_body($resp);
        $data = json_decode($body, true);
        $ok   = ($code >= 200 && $code < 300);
        $err  = null;
        if (!$ok) {
            $err = is_array($data) && !empty($data['code']) ? (string) $data['code'] : ('HTTP ' . $code);
        }
        return array('ok' => $ok, 'code' => $code, 'data' => $data, 'body' => $body, 'error' => $err);
    }

    
    
    

    public function authenticate(array $creds) {
        $tok = $this->token();
        return array('ok' => !empty($tok['ok']), 'auth_token' => $tok['token'] ?? null, 'expires_at' => null, 'error' => $tok['error'] ?? null);
    }

    
    public function create_voucher(array $payload) {
        $order_id = (int) ($payload['order_id'] ?? 0);
        $order    = $order_id && function_exists('wc_get_order') ? wc_get_order($order_id) : null;

        $locker = '';
        if ($order) {
            $locker = trim((string) $order->get_meta('_boxnow_locker_id'));
        }
        if ($locker === '' && !empty($payload['locker_id'])) {
            $locker = (string) $payload['locker_id'];
        }
        if ($locker === '') {
            return array('ok' => false, 'error' => __('No BOX NOW locker selected on this order (_boxnow_locker_id is empty).', 'ai-eshop-optimizer'));
        }

        $warehouse = (string) $this->get_setting('warehouse_id', '');
        if ($warehouse === '') {
            return array('ok' => false, 'error' => __('Origin/warehouse location ID not set in BOX NOW settings.', 'ai-eshop-optimizer'));
        }

        $recipient = isset($payload['recipient']) && is_array($payload['recipient']) ? $payload['recipient'] : array();
        $cod       = (float) ($payload['cod_amount'] ?? 0);
        $pieces    = max(1, (int) ($payload['pieces'] ?? 1));
        $weight_kg = (float) ($payload['weight'] ?? 0);
        $weight_g  = $weight_kg > 0 ? (int) round($weight_kg * 1000) : 0;
        $compart   = (int) ($this->get_setting('default_compartment', '1') ?: 1);
        $invoice   = $order ? (float) $order->get_total() : (float) ($payload['invoice_value'] ?? 0);

        
        $ref = (string) ($payload['reference_1'] ?? ($order ? $order->get_order_number() : (string) $order_id));
        $ref = $ref . '-' . substr(md5(uniqid('', true)), 0, 5);

        $items = array();
        for ($i = 1; $i <= $pieces; $i++) {
            $items[] = array(
                'id'              => (string) $i,
                'name'            => 'parcel',
                'value'           => number_format($pieces > 0 ? $invoice / $pieces : $invoice, 2, '.', ''),
                'compartmentSize' => $compart,
                'weight'          => $weight_g,
            );
        }

        $body = array(
            'orderNumber'         => $ref,
            'invoiceValue'        => number_format($invoice, 2, '.', ''),
            'paymentMode'         => $cod > 0 ? 'cod' : 'prepaid',
            'amountToBeCollected' => number_format($cod, 2, '.', ''),
            'origin'              => array(
                'locationId'    => $warehouse,
                'contactName'   => (string) ($this->get_setting('origin_contact_name', '')  ?: get_bloginfo('name')),
                'contactEmail'  => (string) ($this->get_setting('origin_contact_email', '') ?: get_option('admin_email')),
                'contactNumber' => (string) $this->get_setting('origin_contact_phone', ''),
            ),
            'destination'         => array(
                'locationId'    => $locker,
                'contactName'   => (string) ($recipient['name'] ?? ''),
                'contactEmail'  => (string) ($recipient['email'] ?? ''),
                'contactNumber' => (string) ($recipient['phone'] ?? ''),
            ),
            'items'               => $items,
        );

        $r = $this->request('POST', $this->api_base() . '/api/v1/delivery-requests', array('body' => $body));
        if (empty($r['ok'])) {
            return array('ok' => false, 'error' => sprintf(__('BOX NOW create failed: %s', 'ai-eshop-optimizer'), $r['error'] ?? 'unknown'), 'raw' => $r['data'] ?? null);
        }
        $parcels = isset($r['data']['parcels']) && is_array($r['data']['parcels']) ? $r['data']['parcels'] : array();
        $ids = array();
        foreach ($parcels as $p) {
            if (!empty($p['id'])) { $ids[] = (string) $p['id']; }
        }
        if (empty($ids)) {
            return array('ok' => false, 'error' => __('BOX NOW returned no parcel ids.', 'ai-eshop-optimizer'), 'raw' => $r['data']);
        }
        return array(
            'ok'          => true,
            'voucher_no'  => $ids[0],
            'subvouchers' => $ids,
            'job_id'      => isset($r['data']['id']) ? (string) $r['data']['id'] : null,
            'error'       => null,
            'raw'         => $r['data'],
        );
    }

    
    public function get_label_pdf($voucher_no, $format = 'A4') {
        $ext = (strtoupper((string) $format) === 'THERMAL') ? 'zpl' : 'pdf';
        $accept = $ext === 'pdf' ? 'application/pdf' : 'application/octet-stream';
        $url = $this->api_base() . '/api/v1/parcels/' . rawurlencode((string) $voucher_no) . '/label.' . $ext;
        $r = $this->request('GET', $url, array('accept' => $accept));
        if (empty($r['ok'])) {
            return array('ok' => false, 'pdf' => null, 'error' => sprintf(__('BOX NOW label failed: %s', 'ai-eshop-optimizer'), $r['error'] ?? 'unknown'));
        }
        return array('ok' => true, 'pdf' => $r['body'], 'error' => null);
    }

    public function cancel($voucher_no) {
        $url = $this->api_base() . '/api/v1/parcels/' . rawurlencode((string) $voucher_no) . ':cancel';
        $r = $this->request('POST', $url, array('body' => new stdClass()));
        if (empty($r['ok'])) {
            return array('ok' => false, 'error' => sprintf(__('BOX NOW cancel failed: %s', 'ai-eshop-optimizer'), $r['error'] ?? 'unknown'));
        }
        return array('ok' => true, 'error' => null);
    }

    public function track($voucher_no) {
        $url = $this->api_base() . '/api/v1/parcels/' . rawurlencode((string) $voucher_no);
        $r = $this->request('GET', $url);
        if (empty($r['ok'])) {
            
            
            
            return array('ok' => true, 'status_code' => '', 'checkpoints' => array(), 'consignee' => null, 'delivered_at' => null, 'error' => null);
        }
        $d = is_array($r['data']) ? $r['data'] : array();
        $status = (string) ($d['status'] ?? ($d['state'] ?? ''));
        $checkpoints = array();
        $events = isset($d['events']) && is_array($d['events']) ? $d['events'] : (isset($d['history']) && is_array($d['history']) ? $d['history'] : array());
        foreach ($events as $ev) {
            $ts = isset($ev['createdAt']) ? strtotime((string) $ev['createdAt']) : (isset($ev['timestamp']) ? strtotime((string) $ev['timestamp']) : 0);
            $checkpoints[] = array(
                'code'          => (string) ($ev['type'] ?? ($ev['status'] ?? '')),
                'description'   => (string) ($ev['description'] ?? ($ev['message'] ?? '')),
                'location'      => (string) ($ev['location'] ?? ''),
                'checkpoint_at' => $ts ?: 0,
            );
        }
        $delivered = null;
        if (in_array(strtolower($status), array('delivered', 'completed'), true)) {
            $delivered = isset($d['deliveredAt']) ? strtotime((string) $d['deliveredAt']) : null;
        }
        return array(
            'ok'           => true,
            'status_code'  => $status,
            'checkpoints'  => $checkpoints,
            'consignee'    => $d['recipientName'] ?? null,
            'delivered_at' => $delivered ?: null,
            'error'        => null,
        );
    }

    
    public function shop_list() {
        $r = $this->request('GET', $this->location_base() . '/api/v1/destinations');
        if (empty($r['ok'])) {
            return array('ok' => false, 'shops' => array(), 'error' => $r['error'] ?? 'unknown');
        }
        
        $env  = is_array($r['data']) ? $r['data'] : array();
        $list = isset($env['data']) && is_array($env['data']) ? $env['data'] : $env;
        $shops = array();
        foreach ($list as $loc) {
            if (!is_array($loc) || empty($loc['id'])) { continue; }
            $shops[] = array(
                'id'      => (string) $loc['id'],
                'name'    => (string) ($loc['name'] ?? ''),
                'address' => (string) ($loc['title'] ?? ($loc['address'] ?? '')),
                'zip'     => (string) ($loc['postalCode'] ?? ''),
                'city'    => (string) ($loc['locationName'] ?? ($loc['region'] ?? ($loc['city'] ?? ''))),
            );
        }
        return array('ok' => true, 'shops' => $shops, 'error' => null);
    }

    
    
    

    public static function read_parcel_ids_from_order($order_id) {
        $order = function_exists('wc_get_order') ? wc_get_order((int) $order_id) : null;
        if (!$order) { return array(); }

        $ids = array();
        $multi = $order->get_meta('_boxnow_parcel_ids');
        if (is_array($multi)) {
            foreach ($multi as $pid) {
                $pid = trim((string) $pid);
                if ($pid !== '') { $ids[] = $pid; }
            }
        } elseif (is_string($multi) && $multi !== '') {
            $decoded = json_decode($multi, true);
            if (is_array($decoded)) {
                foreach ($decoded as $pid) {
                    $pid = trim((string) $pid);
                    if ($pid !== '') { $ids[] = $pid; }
                }
            } else {
                $ids[] = $multi;
            }
        }
        $single = trim((string) $order->get_meta('_boxnow_parcel_id'));
        if ($single !== '' && !in_array($single, $ids, true)) { $ids[] = $single; }

        return array_values(array_unique($ids));
    }

    public static function mirror_order($order_id) {
        if (!class_exists('AIEO_Fulfillment_Vouchers')) { return 0; }
        $ids = self::read_parcel_ids_from_order($order_id);
        $created = 0;
        foreach ($ids as $pid) {
            $existing = AIEO_Fulfillment_Vouchers::find_by_voucher_no('boxnow', $pid);
            if ($existing) { continue; }
            $r = AIEO_Fulfillment_Vouchers::create(array(
                'order_id'   => (int) $order_id,
                'carrier'    => 'boxnow',
                'voucher_no' => $pid,
                'status'     => 'created',
            ));
            if (!empty($r['ok'])) { $created++; }
        }
        return $created;
    }
}

add_filter('aieo_fulfillment_couriers', static function (array $drivers) {
    if (!isset($drivers['boxnow']) && class_exists('AIEO_Courier_Driver_BoxNow')) {
        $drivers['boxnow'] = new AIEO_Courier_Driver_BoxNow();
    }
    return $drivers;
});
