<?php

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

class AIEO_DMM_Offer_Attributor {

    private static $instance = null;
    public static function instance() {
        if (self::$instance === null) { self::$instance = new self(); }
        return self::$instance;
    }

    private function __construct() {
        
        
        
        
        if ( defined( 'AIEO_RUNTIME_OWNS_AJAX' ) ) { return; }

        
        
        add_action('woocommerce_checkout_order_processed', array($this, 'capture'), 20, 1);
        
        
        
        add_action('woocommerce_new_order', array($this, 'capture_via_new_order'), 20, 2);
    }

    
    private static $captured = array();

    public function capture($order_id, $posted_data = array(), $order = null) {
        $order_id = (int) $order_id;
        if (!$order_id || isset(self::$captured[$order_id])) { return; }
        self::$captured[$order_id] = true;
        $this->record_attributions_for_order($order_id);
    }

    public function capture_via_new_order($order_id, $order = null) {
        $order_id = (int) $order_id;
        if (!$order_id || isset(self::$captured[$order_id])) { return; }
        self::$captured[$order_id] = true;
        $this->record_attributions_for_order($order_id);
    }

    
    private function record_attributions_for_order($order_id) {
        if (!function_exists('wc_get_order')) { return; }
        $order = wc_get_order($order_id);
        if (!$order) { return; }

        $rows = array();
        $entry_channel     = $this->resolve_entry_channel($order);
        $entry_branch_id   = $this->resolve_entry_branch_id($order);
        $entry_campaign_id = $this->resolve_entry_campaign_id($order);
        $user_id    = (int) $order->get_user_id();
        $order_total = (float) $order->get_total();

        
        
        
        foreach ($order->get_items() as $line) {
            $offer_id = (int) $line->get_meta('_aieo_dmm_gift_offer_id', true);
            if ($offer_id <= 0) { continue; }
            $product_id = (int) ($line->get_variation_id() ?: $line->get_product_id());
            $product = wc_get_product($product_id);
            if (!$product) { continue; }
            $retail = (float) $product->get_regular_price();
            list($cogs, $basis) = AIEO_DMM_Offer_Matcher::product_cost($product_id);
            
            $qty = max(1, (int) $line->get_quantity());
            $rows[] = array(
                'order_id'         => $order_id,
                'offer_id'         => $offer_id,
                'offer_type'       => 'gift',
                'offer_label'      => $this->offer_label($offer_id, 'gift', $product->get_name()),
                'applied_value'    => round($retail * $qty, 2),
                'actual_cost'      => round($cogs * $qty, 2),
                'cost_basis'       => $basis,
                'order_total'      => $order_total,
                'entry_channel'    => $entry_channel,
                'entry_campaign_id'=> $entry_campaign_id,
                'entry_branch_id'  => $entry_branch_id,
                'user_id'          => $user_id,
                'target_product_id'=> $product_id,
            );
        }

        
        
        
        
        
        $active_discounts = $this->load_active_discount_offers();
        if (!empty($active_discounts)) {
            foreach ($order->get_items() as $line) {
                $product_id = (int) $line->get_product_id(); 
                if ($product_id <= 0) { continue; }
                $matched = AIEO_DMM_Offer_Matcher::for_product($product_id, $active_discounts);
                if (empty($matched)) { continue; }
                $product = wc_get_product($product_id);
                if (!$product) { continue; }
                $regular = (float) $product->get_regular_price();
                $line_total = (float) $line->get_total();
                $line_qty   = max(1, (int) $line->get_quantity());
                $forgone    = max(0, ($regular * $line_qty) - $line_total);
                if ($forgone <= 0) { continue; }
                
                
                usort($matched, function($a, $b) {
                    $pa = isset($a['payload']) && is_array(json_decode((string) $a['payload'], true))
                        ? (float) (json_decode((string) $a['payload'], true)['discount_value'] ?? 0)
                        : (float) ($a['percent'] ?? 0);
                    $pb = isset($b['payload']) && is_array(json_decode((string) $b['payload'], true))
                        ? (float) (json_decode((string) $b['payload'], true)['discount_value'] ?? 0)
                        : (float) ($b['percent'] ?? 0);
                    return $pb <=> $pa;
                });
                $offer = $matched[0];
                $offer_id = (int) ($offer['legacy_id'] > 0 ? $offer['legacy_id'] : $offer['id']);
                $rows[] = array(
                    'order_id'         => $order_id,
                    'offer_id'         => $offer_id,
                    'offer_type'       => 'discount',
                    'offer_label'      => $this->offer_label($offer_id, 'discount', (string) ($offer['label'] ?? '')),
                    'applied_value'    => round($forgone, 2),
                    'actual_cost'      => round($forgone, 2),
                    'cost_basis'       => 'forgone_revenue',
                    'order_total'      => $order_total,
                    'entry_channel'    => $entry_channel,
                    'entry_campaign_id'=> $entry_campaign_id,
                    'entry_branch_id'  => $entry_branch_id,
                    'user_id'          => $user_id,
                    'target_product_id'=> $product_id,
                );
            }
        }

        
        
        
        
        
        
        $shipping_total = (float) $order->get_shipping_total();
        $shipping_lines = $order->get_shipping_methods();
        if ($shipping_total <= 0 && !empty($shipping_lines)) {
            $active_fs = $this->load_active_free_shipping_offers();
            if (!empty($active_fs)) {
                $cart_items = $this->order_to_cart_shape($order);
                $matched_fs = AIEO_DMM_Offer_Matcher::for_cart($cart_items, $active_fs);
                foreach ($matched_fs as $rule) {
                    if (empty($rule['_qualified'])) { continue; }
                    $offer_id = (int) $rule['id'];
                    $rows[] = array(
                        'order_id'         => $order_id,
                        'offer_id'         => $offer_id,
                        'offer_type'       => 'free_shipping',
                        'offer_label'      => $this->offer_label($offer_id, 'free_shipping', (string) ($rule['label'] ?? '')),
                        'applied_value'    => 0.00,         
                        'actual_cost'      => null,         
                        'cost_basis'       => 'forgone_revenue',
                        'order_total'      => $order_total,
                        'entry_channel'    => $entry_channel,
                        'entry_campaign_id'=> $entry_campaign_id,
                        'entry_branch_id'  => $entry_branch_id,
                        'user_id'          => $user_id,
                        'target_product_id'=> 0,
                    );
                }
            }
        }

        
        
        
        
        
        
        
        if (class_exists('AIEO_DMM_Exit_Intent')) {
            $ei_codes = AIEO_DMM_Exit_Intent::configured_coupon_codes();
            if (!empty($ei_codes)) {
                $applied = array_map('strtolower', (array) $order->get_coupon_codes());
                $matched = array_values(array_intersect($ei_codes, $applied));
                if (!empty($matched)) {
                    foreach ($matched as $code) {
                        $discount = $this->coupon_discount_on_order($order, $code);
                        $rows[] = array(
                            'order_id'          => $order_id,
                            'offer_id'          => 0,
                            'offer_type'        => 'exit_intent',
                            
                            
                            'offer_label'       => $code,
                            'applied_value'     => round($discount, 2),
                            'actual_cost'       => round($discount, 2),
                            'cost_basis'        => 'forgone_revenue',
                            'order_total'       => $order_total,
                            'entry_channel'     => $entry_channel,
                            'entry_campaign_id' => $entry_campaign_id,
                            'entry_branch_id'   => $entry_branch_id,
                            'user_id'           => $user_id,
                            'target_product_id' => 0,
                        );
                    }
                }
            }
        }

        if (empty($rows)) { return; }

        
        global $wpdb;
        $tbl = $wpdb->prefix . 'aieo_dmm_offer_attributions';
        if (!aieo_dmm_table_exists($tbl)) { return; }
        foreach ($rows as $row) {
            $wpdb->insert($tbl, $row);
        }
    }

    
    private function resolve_entry_channel($order) {
        
        
        
        
        if ( class_exists( 'AIEO_Order_Facts' ) ) {
            $ch = AIEO_Order_Facts::channel( (int) $order->get_id() );
            if ( null !== $ch && '' !== $ch ) { return $ch; }
        }
        
        
        $val = (string) $order->get_meta('_aieo_entry_channel', true);
        return $val !== '' ? $val : 'unattributed';
    }

    
    private function resolve_entry_branch_id($order) {
        static $map = null;

        $soft1 = (string) $order->get_meta('soft1_branches', true);
        if ($soft1 === '') { return null; }
        
        
        
        if (strpos($soft1, ',') !== false) {
            $parts = array_filter(array_map('trim', explode(',', $soft1)));
            $soft1 = (string) reset($parts);
        }
        $soft1 = (int) $soft1;
        if ($soft1 <= 0) { return null; }

        if ($map === null) {
            global $wpdb;
            $tbl = $wpdb->prefix . 'aieo_dmm_branches';
            if (!aieo_dmm_table_exists($tbl)) { return null; }
            $rows = $wpdb->get_results(
                "SELECT id, soft1_id FROM {$tbl} WHERE soft1_id IS NOT NULL",
                ARRAY_A
            );
            $map = array();
            if (is_array($rows)) {
                foreach ($rows as $r) {
                    $map[(int) $r['soft1_id']] = (int) $r['id'];
                }
            }
        }
        return isset($map[$soft1]) ? (int) $map[$soft1] : null;
    }

    
    private function resolve_entry_campaign_id($order) {
        $slug = (string) $order->get_meta('_aieo_entry_campaign', true);
        if ($slug === '') { return null; }
        if (!class_exists('AIEO_DMM_Campaigns')) { return null; }
        $id = AIEO_DMM_Campaigns::id_for_slug($slug);
        return $id ? (int) $id : null;
    }

    
    private function load_active_discount_offers() {
        global $wpdb;
        $tbl = $wpdb->prefix . 'aieo_dmm_offers';
        if (!aieo_dmm_table_exists($tbl)) {
            
            return $this->load_active_legacy_discount_offers();
        }
        $today = current_time('Y-m-d');
        
        $rows = $wpdb->get_results($wpdb->prepare(
            "SELECT * FROM {$tbl}
             WHERE type = 'discount' AND enabled = 1
               AND (start_date IS NULL OR start_date <= %s)
               AND (end_date   IS NULL OR end_date   >= %s)",
            $today, $today
        ), ARRAY_A);
        if (!is_array($rows) || empty($rows)) {
            return $this->load_active_legacy_discount_offers();
        }
        return $rows;
    }

    
    private function load_active_legacy_discount_offers() {
        global $wpdb;
        $tbl = $wpdb->prefix . 'aieo_dmm_brand_discounts';
        if (!aieo_dmm_table_exists($tbl)) { return array(); }
        $today = current_time('Y-m-d');
        
        $rows = $wpdb->get_results($wpdb->prepare(
            "SELECT * FROM {$tbl}
             WHERE enabled = 1
               AND (date_from IS NULL OR date_from <= %s)
               AND (date_to   IS NULL OR date_to   >= %s)",
            $today, $today
        ), ARRAY_A);
        if (!is_array($rows)) { return array(); }
        
        
        
        
        
        
        foreach ($rows as &$r) {
            $bid = isset($r['brand_term_id']) ? (int) $r['brand_term_id'] : 0;
            if (empty($r['brand_term_ids'])) {
                $r['brand_term_ids'] = $bid > 0 ? wp_json_encode(array($bid)) : '[]';
            }
            $r['legacy_id'] = isset($r['id']) ? (int) $r['id'] : 0;
        }
        unset($r);
        return $rows;
    }

    
    private function load_active_free_shipping_offers() {
        global $wpdb;
        $tbl = $wpdb->prefix . 'aieo_dmm_offers';
        if (!aieo_dmm_table_exists($tbl)) { return array(); }
        $today = current_time('Y-m-d');
        
        $rows = $wpdb->get_results($wpdb->prepare(
            "SELECT * FROM {$tbl}
             WHERE type = 'free_shipping' AND enabled = 1
               AND (start_date IS NULL OR start_date <= %s)
               AND (end_date   IS NULL OR end_date   >= %s)",
            $today, $today
        ), ARRAY_A);
        return is_array($rows) ? $rows : array();
    }

    
    private function order_to_cart_shape($order) {
        $items = array();
        foreach ($order->get_items() as $line) {
            $items[] = array(
                'product_id'    => (int) $line->get_product_id(),
                'variation_id'  => (int) $line->get_variation_id(),
                'quantity'      => (int) $line->get_quantity(),
                'line_subtotal' => (float) $line->get_subtotal(),
            );
        }
        return $items;
    }

    
    private function offer_label($offer_id, $offer_type, $fallback = '') {
        if ($fallback !== '') { return $fallback; }
        return $offer_type . '#' . (int) $offer_id;
    }

    
    private function coupon_discount_on_order($order, $code) {
        $code = strtolower((string) $code);
        $sum  = 0.0;
        foreach ($order->get_items('coupon') as $coupon_item) {
            if (strtolower((string) $coupon_item->get_code()) !== $code) { continue; }
            $sum += (float) $coupon_item->get_discount();
            $sum += (float) $coupon_item->get_discount_tax();
        }
        return $sum;
    }
}
