<?php

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

class AIEO_DMM_Offer_Matcher {

    
    
    

    
    public static function for_product($product_id, array $offers) {
        $product_id = (int) $product_id;
        if ($product_id <= 0 || empty($offers)) { return array(); }

        $context = self::product_context($product_id);
        return self::filter($offers, $context);
    }

    
    public static function for_term($taxonomy, $term_id, array $offers) {
        $term_id = (int) $term_id;
        if ($term_id <= 0 || empty($offers)) { return array(); }

        
        
        
        
        $brand_tax = self::brand_taxonomy();
        $key = null;
        if ($taxonomy === $brand_tax || $taxonomy === 'product_brand' || $taxonomy === 'yith_product_brand' || $taxonomy === 'pwb-brand' || $taxonomy === 'product_brands') {
            $key = 'brand_term_ids';
        } elseif ($taxonomy === 'product_cat') {
            $key = 'category_term_ids';
        } elseif ($taxonomy === 'pa_need') {
            $key = 'need_term_ids';
        }
        if ($key === null) { return array(); }

        
        
        
        $context = array(
            'brand_term_ids'    => array(),
            'category_term_ids' => array(),
            'need_term_ids'     => array(),
        );
        $context[$key] = array($term_id);
        return self::filter($offers, $context);
    }

    
    public static function for_cart(array $cart_items, array $offers) {
        if (empty($offers)) { return array(); }

        
        
        
        
        $line_terms = array();
        $cart_total = 0.0;
        $cart_qty   = 0;
        foreach ($cart_items as $key => $item) {
            $pid = !empty($item['variation_id']) ? (int) $item['variation_id'] : (int) ($item['product_id'] ?? 0);
            
            $resolve_id = !empty($item['product_id']) ? (int) $item['product_id'] : $pid;
            $ctx = self::product_context($resolve_id);
            $ctx['product_ids'] = array($resolve_id);
            $line_terms[$key]   = $ctx;
            $cart_total += (float) ($item['line_subtotal'] ?? 0);
            $cart_qty   += (int)   ($item['quantity'] ?? 0);
        }

        $matched = array();
        foreach ($offers as $offer) {
            if (!is_array($offer)) { continue; }

            
            
            $req_products = self::ids($offer, 'product_ids');

            
            
            
            
            
            
            
            
            $targeted_subtotal = 0.0;
            $targeted_qty      = 0;
            $any_line_matches  = false;
            $vetoed            = false;
            $has_required_prod = empty($req_products); 
            foreach ($cart_items as $key => $item) {
                $ctx = isset($line_terms[$key]) ? $line_terms[$key] : array();
                if (self::offer_excludes($offer, $ctx)) { $vetoed = true; }
                if (!empty($req_products)) {
                    $lp = isset($ctx['product_ids']) ? (array) $ctx['product_ids'] : array();
                    if (!empty($lp) && array_intersect($lp, $req_products)) { $has_required_prod = true; }
                }
                if (!self::offer_targets($offer, $ctx)) { continue; }
                if (self::offer_excludes($offer, $ctx)) { continue; }
                $any_line_matches  = true;
                $targeted_subtotal += (float) ($item['line_subtotal'] ?? 0);
                $targeted_qty      += (int)   ($item['quantity'] ?? 0);
            }

            
            
            
            
            $has_targeting = !empty(self::ids($offer, 'brand_term_ids'))
                          || !empty(self::ids($offer, 'category_term_ids'))
                          || !empty(self::ids($offer, 'need_term_ids'))
                          || !empty($req_products);
            if ($has_targeting && !$any_line_matches) {
                continue;
            }

            
            
            $threshold = (float) ($offer['min_subtotal'] ?? 0);
            $scope     = isset($offer['min_subtotal_scope']) ? (string) $offer['min_subtotal_scope'] : 'targeted';
            $check_value = ($scope === 'cart_total') ? $cart_total : $targeted_subtotal;
            $threshold_passed = ($threshold <= 0) || ($check_value >= $threshold);

            
            $min_qty   = (int) ($offer['min_quantity'] ?? 0);
            $qty_scope = isset($offer['min_quantity_scope']) ? (string) $offer['min_quantity_scope'] : 'targeted';
            $check_qty = ($qty_scope === 'cart_total') ? $cart_qty : $targeted_qty;
            $qty_passed = ($min_qty <= 0) || ($check_qty >= $min_qty);

            $offer['_targeted_subtotal'] = $targeted_subtotal;
            $offer['_vetoed']            = $vetoed;
            $offer['_qualified']         = !$vetoed && $has_required_prod && $threshold_passed && $qty_passed;
            $matched[] = $offer;
        }
        return $matched;
    }

    
    public static function offer_excludes(array $offer, array $context) {
        $ex_brand   = self::ids($offer, 'excluded_brand_ids');
        $ex_cat     = self::ids($offer, 'excluded_category_ids');
        $ex_need    = self::ids($offer, 'excluded_need_ids');
        $ex_product = self::ids($offer, 'excluded_product_ids');
        if (empty($ex_brand) && empty($ex_cat) && empty($ex_need) && empty($ex_product)) { return false; }

        $ctx_brand   = isset($context['brand_term_ids'])    ? (array) $context['brand_term_ids']    : array();
        $ctx_cat     = isset($context['category_term_ids']) ? (array) $context['category_term_ids'] : array();
        $ctx_need    = isset($context['need_term_ids'])     ? (array) $context['need_term_ids']     : array();
        $ctx_product = isset($context['product_ids'])       ? (array) $context['product_ids']       : array();

        if (!empty($ex_brand)   && !empty($ctx_brand)   && array_intersect($ctx_brand,   $ex_brand))   { return true; }
        if (!empty($ex_cat)     && !empty($ctx_cat)     && array_intersect($ctx_cat,     $ex_cat))     { return true; }
        if (!empty($ex_need)    && !empty($ctx_need)    && array_intersect($ctx_need,    $ex_need))    { return true; }
        if (!empty($ex_product) && !empty($ctx_product) && array_intersect($ctx_product, $ex_product)) { return true; }
        return false;
    }

    
    public static function offer_targets(array $offer, array $context) {
        $brand_ids    = self::ids($offer, 'brand_term_ids');
        $category_ids = self::ids($offer, 'category_term_ids');
        $need_ids     = self::ids($offer, 'need_term_ids');
        $product_ids  = self::ids($offer, 'product_ids');
        $operator     = (isset($offer['rule_operator']) && strtoupper((string) $offer['rule_operator']) === 'OR') ? 'OR' : 'AND';

        $ctx_brand   = isset($context['brand_term_ids'])    ? (array) $context['brand_term_ids']    : array();
        $ctx_cat     = isset($context['category_term_ids']) ? (array) $context['category_term_ids'] : array();
        $ctx_need    = isset($context['need_term_ids'])     ? (array) $context['need_term_ids']     : array();
        $ctx_product = isset($context['product_ids'])       ? (array) $context['product_ids']       : array();

        
        if (empty($brand_ids) && empty($category_ids) && empty($need_ids)) {
            
            
            
            if (!empty($product_ids)) {
                return !empty($ctx_product) && (bool) array_intersect($ctx_product, $product_ids);
            }
            return true;
        }

        
        
        
        
        if ($operator === 'OR') {
            
            
            
            return (
                (!empty($brand_ids)    && !empty($ctx_brand) && array_intersect($ctx_brand, $brand_ids))
             || (!empty($category_ids) && !empty($ctx_cat)   && array_intersect($ctx_cat,   $category_ids))
             || (!empty($need_ids)     && !empty($ctx_need)  && array_intersect($ctx_need,  $need_ids))
            );
        }

        
        
        $brand_match = empty($brand_ids)    || (!empty($ctx_brand) && array_intersect($ctx_brand, $brand_ids));
        $cat_match   = empty($category_ids) || (!empty($ctx_cat)   && array_intersect($ctx_cat,   $category_ids));
        $need_match  = empty($need_ids)     || (!empty($ctx_need)  && array_intersect($ctx_need,  $need_ids));
        return $brand_match && $cat_match && $need_match;
    }

    
    
    

    
    public static function product_context($product_id) {
        
        
        
        
        static $memo = array();

        $product_id = (int) $product_id;
        if ($product_id <= 0) {
            return array('brand_term_ids' => array(), 'category_term_ids' => array(), 'need_term_ids' => array(), 'product_ids' => array());
        }
        if (isset($memo[$product_id])) { return $memo[$product_id]; }

        $brand_tax = self::brand_taxonomy();
        $brand_terms = wp_get_object_terms($product_id, $brand_tax, array('fields' => 'ids'));
        if (is_wp_error($brand_terms)) { $brand_terms = array(); }

        $cat_terms = wp_get_object_terms($product_id, 'product_cat', array('fields' => 'ids'));
        if (is_wp_error($cat_terms)) { $cat_terms = array(); }

        $need_terms = array();
        if (taxonomy_exists('pa_need')) {
            $need_terms = wp_get_object_terms($product_id, 'pa_need', array('fields' => 'ids'));
            if (is_wp_error($need_terms)) { $need_terms = array(); }
        }

        
        
        
        $self_ids = array($product_id);
        $parent = (int) wp_get_post_parent_id($product_id);
        if ($parent > 0) { $self_ids[] = $parent; }

        return $memo[$product_id] = array(
            'brand_term_ids'    => array_map('intval', (array) $brand_terms),
            'category_term_ids' => array_map('intval', (array) $cat_terms),
            'need_term_ids'     => array_map('intval', (array) $need_terms),
            'product_ids'       => array_map('intval', $self_ids),
        );
    }

    
    private static function filter(array $offers, array $context) {
        $matched = array();
        foreach ($offers as $offer) {
            if (!is_array($offer)) { continue; }
            if (self::offer_targets($offer, $context)) {
                $matched[] = $offer;
            }
        }
        return $matched;
    }

    
    private static function ids(array $offer, $key) {
        if (!isset($offer[$key])) { return array(); }
        $val = $offer[$key];
        if (is_string($val)) {
            $val = json_decode($val, true);
        }
        if (!is_array($val)) { return array(); }
        return array_values(array_filter(array_map('intval', $val)));
    }

    
    public static function resolve_product_tokens($blob) {
        global $wpdb;
        if (!is_string($blob) || trim($blob) === '') { return array(); }

        $tokens = preg_split('/[,;\s]+/', trim($blob), -1, PREG_SPLIT_NO_EMPTY);
        if (empty($tokens)) { return array(); }

        $resolved = array();
        foreach ($tokens as $token) {
            $token = trim($token);
            if ($token === '') { continue; }
            $product_id = 0;

            if (ctype_digit($token)) {
                $candidate = (int) $token;
                $type = get_post_type($candidate);
                if ($type === 'product' || $type === 'product_variation') {
                    $product_id = $candidate;
                }
            }

            if ($product_id === 0 && function_exists('wc_get_product_id_by_sku')) {
                $by_sku = (int) wc_get_product_id_by_sku($token);
                if ($by_sku > 0) { $product_id = $by_sku; }
            }

            if ($product_id === 0) {
                
                $by_barcode = (int) $wpdb->get_var($wpdb->prepare(
                    "SELECT post_id FROM {$wpdb->postmeta}
                     WHERE meta_key = '_global_unique_id' AND meta_value = %s
                     LIMIT 1",
                    $token
                ));
                if ($by_barcode > 0) {
                    $type = get_post_type($by_barcode);
                    if ($type === 'product' || $type === 'product_variation') {
                        $product_id = $by_barcode;
                    }
                }
            }

            if ($product_id <= 0) { continue; }

            if (get_post_type($product_id) === 'product_variation') {
                $parent = (int) wp_get_post_parent_id($product_id);
                if ($parent > 0) { $product_id = $parent; }
            }

            $resolved[$product_id] = true;
        }
        return array_keys($resolved);
    }

    
    public static function format_product_tokens(array $ids) {
        $lines = array();
        foreach ($ids as $pid) {
            $pid = (int) $pid;
            if ($pid <= 0) { continue; }
            $title = get_the_title($pid);
            $sku   = function_exists('get_post_meta') ? (string) get_post_meta($pid, '_sku', true) : '';
            $line  = (string) $pid;
            if ($sku !== '')   { $line .= ' — ' . $sku; }
            if ($title !== '') { $line .= ' — ' . $title; }
            $lines[] = $line;
        }
        return implode("\n", $lines);
    }

    
    public static function product_cost($product_id) {
        global $wpdb;
        $product_id = (int) $product_id;
        if ($product_id <= 0) { return array(0.0, 'unknown_proxy'); }

        
        
        $vitals_table = $wpdb->prefix . 'aieo_core_product_vitals';
        
        $cost = (float) $wpdb->get_var($wpdb->prepare(
            "SELECT cost FROM {$vitals_table} WHERE product_id = %d LIMIT 1",
            $product_id
        ));
        if ($cost > 0) { return array($cost, 'cogs'); }

        
        
        $meta = (string) get_post_meta($product_id, '_cogs_total_value', true);
        $cost = (float) str_replace(',', '.', $meta);
        if ($cost > 0) { return array($cost, 'cogs'); }

        
        $meta = (string) get_post_meta($product_id, '_wc_cog_cost', true);
        $cost = (float) str_replace(',', '.', $meta);
        if ($cost > 0) { return array($cost, 'cogs'); }

        
        $custom = apply_filters('aieo_dmm_product_cost', null, $product_id);
        if ($custom !== null && (float) $custom > 0) {
            return array((float) $custom, 'cogs');
        }

        
        $retail = 0.0;
        if (function_exists('wc_get_product')) {
            $product = wc_get_product($product_id);
            if ($product) { $retail = (float) $product->get_regular_price(); }
        }
        return array($retail, 'unknown_proxy');
    }

    
    private static function brand_taxonomy() {
        if (class_exists('AIEO_DMM_Brand_Discounts')
            && method_exists('AIEO_DMM_Brand_Discounts', 'get_brand_taxonomy')) {
            $tax = AIEO_DMM_Brand_Discounts::get_brand_taxonomy();
            if ($tax) { return $tax; }
        }
        return 'product_brand';
    }
}
