<?php

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

class AIEO_MOI_Order_Mapper {

    
    
    public static function upsert_from_canonical(array $vendor, array $canonical, $context = 'event') {
        global $wpdb;
        $links_tbl = AIEO_MOI_Schema::tables()['order_links'];
        $remote_id = (string) ($canonical['remote_order_id'] ?? '');
        if ($remote_id === '') {
            return array('error' => new WP_Error('no_remote_id', 'Missing remote_order_id'));
        }

        $is_reconcile = ($context === 'reconcile');

        
        $link = $wpdb->get_row($wpdb->prepare(
            "SELECT * FROM {$links_tbl} WHERE vendor_id = %d AND remote_order_id = %s LIMIT 1",
            (int) $vendor['id'], $remote_id
        ), ARRAY_A);

        if ($link && (int) $link['wc_order_id'] > 0) {
            $order = wc_get_order((int) $link['wc_order_id']);
            if ($order) {
                $touched = $is_reconcile
                    ? self::apply_state_and_meta_additive($order, $vendor, $canonical)
                    : (self::apply_state_and_meta($order, $vendor, $canonical) || true);
                
                
                $wpdb->update($links_tbl, array(
                    'remote_state' => substr((string) ($canonical['state'] ?? ''), 0, 40),
                    'updated_at'   => current_time('mysql', true),
                ), array('id' => (int) $link['id']));
                return array(
                    'wc_order_id' => $order->get_id(),
                    'created'     => false,
                    'touched'     => $touched,
                    'order'       => $order,
                );
            }
            
            
            
            
            $wpdb->delete($links_tbl, array('id' => (int) $link['id']));
        }

        
        $order = self::create_wc_order($vendor, $canonical, $context);
        if (is_wp_error($order)) {
            return array('error' => $order);
        }

        
        $wpdb->insert($links_tbl, array(
            'vendor_id'       => (int) $vendor['id'],
            'remote_order_id' => $remote_id,
            'wc_order_id'     => $order->get_id(),
            'remote_state'    => substr((string) ($canonical['state'] ?? ''), 0, 40),
        ));

        return array(
            'wc_order_id' => $order->get_id(),
            'created'     => true,
            'touched'     => true,
            'order'       => $order,
        );
    }

    private static function create_wc_order(array $vendor, array $canonical, $context = 'event') {
        $order = wc_create_order(array('status' => 'pending'));
        if (is_wp_error($order)) { return $order; }

        
        
        
        
        
        
        if (!empty($canonical['created_at'])) {
            $order->set_date_created((int) $canonical['created_at']);
        }

        
        
        
        $imported_via = in_array($context, array('webhook', 'poll', 'reconcile'), true) ? $context : 'event';
        $order->update_meta_data('_aieo_moi_imported_via', $imported_via);
        $order->update_meta_data('_aieo_moi_imported_at',  current_time('mysql', true));

        
        $billing  = isset($canonical['billing'])  && is_array($canonical['billing'])  ? $canonical['billing']  : array();
        $shipping = isset($canonical['shipping']) && is_array($canonical['shipping']) ? $canonical['shipping'] : $billing;
        $order->set_address(self::address_payload($billing),  'billing');
        $order->set_address(self::address_payload($shipping), 'shipping');

        
        foreach ((array) ($canonical['line_items'] ?? array()) as $item) {
            $product_id = self::resolve_product_id($vendor, $item);
            $product    = $product_id ? wc_get_product($product_id) : null;
            $name       = (string) ($item['title'] ?? ($product ? $product->get_name() : 'Marketplace item'));
            $qty        = max(1, (int) ($item['qty'] ?? 1));
            $unit_price = (float) ($item['unit_price'] ?? 0);
            $tax        = (float) ($item['tax'] ?? 0);

            $line_item = new WC_Order_Item_Product();
            $line_item->set_name($name);
            $line_item->set_quantity($qty);
            $line_item->set_subtotal($unit_price * $qty);
            $line_item->set_total($unit_price * $qty);
            $line_item->set_taxes(array('total' => array($tax), 'subtotal' => array($tax)));
            
            
            
            
            
            
            
            
            
            if ($product) {
                try {
                    if ($product->is_type('variation')) {
                        $parent_id = (int) $product->get_parent_id();
                        if ($parent_id > 0) {
                            $line_item->set_variation_id((int) $product->get_id());
                            $line_item->set_product_id($parent_id);
                        }
                    } else {
                        $line_item->set_product_id((int) $product->get_id());
                    }
                } catch (\Throwable $e) {
                    
                    
                }
            }
            $order->add_item($line_item);
        }

        
        $shipping_total = (float) ($canonical['totals']['shipping'] ?? 0);
        if ($shipping_total > 0 || !empty($canonical['courier'])) {
            $ship_item = new WC_Order_Item_Shipping();
            $ship_item->set_method_title((string) ($canonical['courier'] ?? __('Marketplace shipping', 'marketplace-order-importer')));
            $ship_item->set_method_id('moi_marketplace');
            $ship_item->set_total($shipping_total);
            $order->add_item($ship_item);
        }

        
        self::apply_state_and_meta($order, $vendor, $canonical);

        $order->calculate_totals(false);
        $order->update_status(self::wc_status_from_vendor($vendor), sprintf(
            
            __('Imported from %s.', 'marketplace-order-importer'),
            $vendor['label']
        ));

        return $order;
    }

    private static function apply_state_and_meta(WC_Order $order, array $vendor, array $canonical) {
        $order->update_meta_data('_aieo_moi_vendor_id',       (int) $vendor['id']);
        $order->update_meta_data('_aieo_moi_vendor_slug',     (string) $vendor['slug']);
        $order->update_meta_data('_aieo_moi_provider',        (string) $vendor['provider']);
        $order->update_meta_data('_aieo_moi_remote_order_id', (string) ($canonical['remote_order_id'] ?? ''));
        $order->update_meta_data('_aieo_moi_remote_code',     (string) ($canonical['remote_code'] ?? ''));
        $order->update_meta_data('_aieo_moi_state',           (string) ($canonical['state'] ?? ''));
        $order->update_meta_data('_aieo_moi_courier',         (string) ($canonical['courier'] ?? ''));
        $order->update_meta_data('_aieo_moi_voucher_url',     (string) ($canonical['voucher_url'] ?? ''));
        $order->update_meta_data('_aieo_moi_tracking_codes',  wp_json_encode((array) ($canonical['tracking_codes'] ?? array())));
        $order->update_meta_data('_aieo_moi_gift_wrap',       !empty($canonical['gift_wrap']) ? 'yes' : 'no');
        
        
        
        
        if (isset($canonical['accept_options']) && is_array($canonical['accept_options'])) {
            $order->update_meta_data('_aieo_moi_accept_options', wp_json_encode($canonical['accept_options']));
        }
        if (!empty($canonical['invoice']) && is_array($canonical['invoice'])) {
            
            
            $inv = $canonical['invoice'];
            $order->update_meta_data('_aieo_moi_invoice_data', wp_json_encode($inv));
            if (!empty($inv['vat']))     { $order->update_meta_data('_billing_vat',       (string) $inv['vat']); }
            if (!empty($inv['doy']))     { $order->update_meta_data('_billing_irs',       (string) $inv['doy']); }
            if (!empty($inv['profession'])) { $order->update_meta_data('_billing_store',  (string) $inv['profession']); }
            if (!empty($inv['company'])) { $order->set_billing_company((string) $inv['company']); }
            $order->update_meta_data('_billing_timologio', 'YES');
        }

        
        
        
        
        
        
        
        if (class_exists('AIEO_MOI_Order_Meta_Box') && (string) $vendor['provider'] !== '') {
            AIEO_MOI_Order_Meta_Box::seed_attribution_meta($order, (string) $vendor['provider']);
        }

        $order->save();
    }

    
    private static function apply_state_and_meta_additive(WC_Order $order, array $vendor, array $canonical) {
        $touched = false;

        $additive = function ($key, $value) use ($order, &$touched) {
            $value = (string) $value;
            if ($value === '') { return; }
            $existing = (string) $order->get_meta($key, true);
            if ($existing === '') {
                $order->update_meta_data($key, $value);
                $touched = true;
            }
        };

        
        
        
        
        $identity = array(
            '_aieo_moi_vendor_id'       => (int) $vendor['id'],
            '_aieo_moi_vendor_slug'     => (string) $vendor['slug'],
            '_aieo_moi_provider'        => (string) $vendor['provider'],
            '_aieo_moi_remote_order_id' => (string) ($canonical['remote_order_id'] ?? ''),
        );
        foreach ($identity as $k => $v) {
            $existing = (string) $order->get_meta($k, true);
            if ((string) $v !== '' && $existing !== (string) $v) {
                $order->update_meta_data($k, $v);
                $touched = true;
            }
        }

        
        
        
        $additive('_aieo_moi_remote_code',    (string) ($canonical['remote_code']    ?? ''));
        $additive('_aieo_moi_state',          (string) ($canonical['state']          ?? ''));
        $additive('_aieo_moi_courier',        (string) ($canonical['courier']        ?? ''));
        $additive('_aieo_moi_voucher_url',    (string) ($canonical['voucher_url']    ?? ''));

        $tracking = (array) ($canonical['tracking_codes'] ?? array());
        if (!empty($tracking)) {
            $existing_json = (string) $order->get_meta('_aieo_moi_tracking_codes', true);
            $existing_arr  = $existing_json !== '' ? (array) json_decode($existing_json, true) : array();
            if (empty($existing_arr)) {
                $order->update_meta_data('_aieo_moi_tracking_codes', wp_json_encode($tracking));
                $touched = true;
            }
        }

        
        
        if (!empty($canonical['invoice']) && is_array($canonical['invoice'])) {
            $existing_inv = (string) $order->get_meta('_aieo_moi_invoice_data', true);
            if ($existing_inv === '') {
                $inv = $canonical['invoice'];
                $order->update_meta_data('_aieo_moi_invoice_data', wp_json_encode($inv));
                if (!empty($inv['vat']))         { $additive('_billing_vat',   (string) $inv['vat']); }
                if (!empty($inv['doy']))         { $additive('_billing_irs',   (string) $inv['doy']); }
                if (!empty($inv['profession']))  { $additive('_billing_store', (string) $inv['profession']); }
                if (!empty($inv['company']) && $order->get_billing_company() === '') {
                    $order->set_billing_company((string) $inv['company']);
                    $touched = true;
                }
                if ((string) $order->get_meta('_billing_timologio', true) === '') {
                    $order->update_meta_data('_billing_timologio', 'YES');
                    $touched = true;
                }
            }
        }

        if ($touched) { $order->save(); }
        return $touched;
    }

    private static function address_payload(array $a) {
        return array(
            'first_name' => isset($a['first_name']) ? (string) $a['first_name'] : '',
            'last_name'  => isset($a['last_name'])  ? (string) $a['last_name']  : '',
            'company'    => isset($a['company'])    ? (string) $a['company']    : '',
            'address_1'  => isset($a['address_1'])  ? (string) $a['address_1']  : '',
            'address_2'  => isset($a['address_2'])  ? (string) $a['address_2']  : '',
            'city'       => isset($a['city'])       ? (string) $a['city']       : '',
            'state'      => isset($a['state'])      ? (string) $a['state']      : '',
            'postcode'   => isset($a['postcode'])   ? (string) $a['postcode']   : '',
            'country'    => isset($a['country'])    ? (string) $a['country']    : 'GR',
            'email'      => isset($a['email'])      ? (string) $a['email']      : '',
            'phone'      => isset($a['phone'])      ? (string) $a['phone']      : '',
        );
    }

    
    private static function resolve_product_id(array $vendor, array $item) {
        $remote_id = (string) ($item['remote_id'] ?? '');
        if ($remote_id === '') { return 0; }

        $strategy = isset($vendor['sku_strategy']) ? (string) $vendor['sku_strategy'] : 'sku';
        switch ($strategy) {
            case 'id':
                $pid = (int) $remote_id;
                return wc_get_product($pid) ? $pid : 0;

            case 'sku':
                if (function_exists('wc_get_product_id_by_sku')) {
                    $pid = (int) wc_get_product_id_by_sku($remote_id);
                    if ($pid > 0) { return $pid; }
                }
                return 0;

            case 'custom_field':
                $key = isset($vendor['sku_meta_key']) ? (string) $vendor['sku_meta_key'] : '';
                if ($key === '') { return 0; }
                global $wpdb;
                $pid = (int) $wpdb->get_var($wpdb->prepare(
                    "SELECT post_id FROM {$wpdb->postmeta}
                     WHERE meta_key = %s AND meta_value = %s LIMIT 1",
                    $key, $remote_id
                ));
                return $pid;
        }
        return 0;
    }

    private static function wc_status_from_vendor(array $vendor) {
        $status = (string) ($vendor['default_order_status'] ?? 'wc-on-hold');
        return strpos($status, 'wc-') === 0 ? substr($status, 3) : $status;
    }
}
