<?php

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

class AIEO_DMM_Product_FP {

    
    private static $l1 = array();

    
    public static function get($product_id) {
        $product_id = (int) $product_id;
        if ($product_id <= 0) {
            return null;
        }
        if (isset(self::$l1[$product_id])) {
            return self::$l1[$product_id];
        }

        global $wpdb;
        $table = $wpdb->prefix . 'aieo_dmm_product_fp';
        if (!self::table_exists($table)) {
            return null;
        }

        
        $row = $wpdb->get_row($wpdb->prepare("SELECT * FROM {$table} WHERE product_id = %d", $product_id), ARRAY_A);

        $current_key = self::current_version_key();
        if (!$row || !isset($row['fp_version_key']) || $row['fp_version_key'] !== $current_key) {
            $row = self::compute($product_id, $current_key);
        } else {
            $row = self::hydrate_row($row);
        }

        self::$l1[$product_id] = $row;
        return $row;
    }

    
    public static function compute($product_id, $version_key = null) {
        $product_id = (int) $product_id;
        if ($product_id <= 0) {
            return null;
        }
        if ($version_key === null) {
            $version_key = self::current_version_key();
        }

        if (!function_exists('wc_get_product')) {
            return null;
        }
        $product = wc_get_product($product_id);
        if (!$product) {
            return null;
        }

        $parent_id    = $product->is_type('variation') ? (int) $product->get_parent_id() : 0;
        $base_regular = is_numeric($product->get_regular_price('edit')) ? (float) $product->get_regular_price('edit') : 0.0;
        $base_sale    = is_numeric($product->get_sale_price('edit')) ? (float) $product->get_sale_price('edit') : 0.0;

        $brand_taxonomy = class_exists('AIEO_DMM_Brand_Discounts')
            ? AIEO_DMM_Brand_Discounts::get_brand_taxonomy()
            : 'product_brand';
        if (!$brand_taxonomy) { $brand_taxonomy = 'product_brand'; }

        $brand_term_ids = self::get_term_ids($product_id, $brand_taxonomy);
        $cat_term_ids   = self::get_term_ids($product_id, 'product_cat');
        $need_term_ids  = taxonomy_exists('pa_need') ? self::get_term_ids($product_id, 'pa_need') : array();

        $self_ids = array((int) $product_id);
        if ($parent_id > 0) { $self_ids[] = (int) $parent_id; }
        list($brand_pct, $cat_pct, $combined_pct) = self::resolve_discount_pcts($brand_term_ids, $cat_term_ids, $need_term_ids, $self_ids);
        $schedule_pct = self::resolve_schedule_pct($product_id);
        $nfs_excluded = self::resolve_nfs_excluded($product_id, $parent_id);
        $gift_ids     = self::resolve_gift_offer_ids($brand_term_ids, $cat_term_ids);

        $data = array(
            'product_id'              => $product_id,
            'parent_id'               => $parent_id,
            'base_regular'            => $base_regular,
            'base_sale'               => $base_sale,
            'brand_term_ids'          => wp_json_encode(array_values($brand_term_ids)),
            'cat_term_ids'            => wp_json_encode(array_values($cat_term_ids)),
            'effective_brand_pct'     => $brand_pct,
            'effective_cat_pct'       => $cat_pct,
            'effective_combined_pct'  => $combined_pct,
            'active_schedule_pct'     => $schedule_pct,
            'nfs_excluded'            => $nfs_excluded ? 1 : 0,
            'eligible_gift_offer_ids' => wp_json_encode(array_values($gift_ids)),
            'fp_version_key'          => (string) $version_key,
            'computed_at'             => current_time('mysql', true),
        );
        $formats = array('%d', '%d', '%f', '%f', '%s', '%s', '%f', '%f', '%f', '%f', '%d', '%s', '%s', '%s');

        global $wpdb;
        $table = $wpdb->prefix . 'aieo_dmm_product_fp';
        $wpdb->replace($table, $data, $formats);

        return self::hydrate_row($data);
    }

    
    public static function on_product_save($post_id) {
        $post_id = (int) $post_id;
        if ($post_id <= 0) { return; }
        
        if (function_exists('wp_is_post_autosave') && wp_is_post_autosave($post_id)) { return; }
        if (function_exists('wp_is_post_revision') && wp_is_post_revision($post_id)) { return; }
        
        self::compute($post_id);
        
        $parent = (int) wp_get_post_parent_id($post_id);
        if ($parent > 0) {
            self::compute($parent);
        }
    }

    
    public static function clear_memo() {
        self::$l1 = array();
    }

    
    
    

    
    private static function resolve_discount_pcts(array $brand_term_ids, array $cat_term_ids, array $need_term_ids = array(), array $self_ids = array()) {
        if (!class_exists('AIEO_DMM_Pricing_Engine')) {
            return array(0.0, 0.0, 0.0);
        }
        $engine = AIEO_DMM_Pricing_Engine::instance();
        if (!method_exists($engine, 'load_brand_discount_rules')) {
            return array(0.0, 0.0, 0.0);
        }
        $rules = $engine->load_brand_discount_rules();
        if (empty($rules)) {
            return array(0.0, 0.0, 0.0);
        }

        $brand_max = 0.0;
        $cat_max   = 0.0;
        $combined  = 0.0;

        foreach ($rules as $rule) {
            
            
            
            
            if ((float) (isset($rule['min_subtotal']) ? $rule['min_subtotal'] : 0) > 0) { continue; }
            if (!empty($rule['product_ids'])) { continue; }
            if (!empty($rule['excluded_brand_ids'])    && !empty($brand_term_ids) && array_intersect($brand_term_ids, $rule['excluded_brand_ids']))    { continue; }
            if (!empty($rule['excluded_category_ids']) && !empty($cat_term_ids)   && array_intersect($cat_term_ids,   $rule['excluded_category_ids'])) { continue; }
            if (!empty($rule['excluded_need_ids'])     && !empty($need_term_ids)  && array_intersect($need_term_ids,  $rule['excluded_need_ids']))     { continue; }
            if (!empty($rule['excluded_product_ids'])  && !empty($self_ids)       && array_intersect($self_ids,       $rule['excluded_product_ids']))  { continue; }

            $has_brand_filter = !empty($rule['brand_term_id']);
            $has_cat_filter   = !empty($rule['category_term_ids']);
            $rule_need_ids    = isset($rule['need_term_ids']) && is_array($rule['need_term_ids']) ? $rule['need_term_ids'] : array();
            $has_need_filter  = !empty($rule_need_ids);

            
            
            
            if ($rule['operator'] === 'OR') {
                $match = ($has_brand_filter && in_array((int) $rule['brand_term_id'], $brand_term_ids, true))
                      || ($has_cat_filter   && !empty($cat_term_ids)  && array_intersect($rule['category_term_ids'], $cat_term_ids))
                      || ($has_need_filter  && !empty($need_term_ids) && array_intersect($rule_need_ids,             $need_term_ids));
                if (!$has_brand_filter && !$has_cat_filter && !$has_need_filter) { $match = false; }
            } else {
                $brand_match = !$has_brand_filter
                    || (!empty($brand_term_ids) && in_array((int) $rule['brand_term_id'], $brand_term_ids, true));
                $cat_match   = !$has_cat_filter
                    || (!empty($cat_term_ids) && array_intersect($rule['category_term_ids'], $cat_term_ids));
                $need_match  = !$has_need_filter
                    || (!empty($need_term_ids) && array_intersect($rule_need_ids, $need_term_ids));
                $match = $brand_match && $cat_match && $need_match;
            }

            if (!$match) { continue; }

            $pct = (float) $rule['percent'];
            if ($pct > $combined) { $combined = $pct; }

            
            if ($has_brand_filter && !$has_cat_filter && !$has_need_filter && $pct > $brand_max) { $brand_max = $pct; }
            if ($has_cat_filter   && !$has_brand_filter && !$has_need_filter && $pct > $cat_max) { $cat_max  = $pct; }
        }
        return array($brand_max, $cat_max, $combined);
    }

    private static function resolve_schedule_pct($product_id) {
        global $wpdb;
        $table = $wpdb->prefix . 'aieo_dmm_discount_schedules';
        if (!self::table_exists($table)) {
            return 0.0;
        }
        $today = current_time('Y-m-d');
        
        $pct = $wpdb->get_var($wpdb->prepare(
            "SELECT MAX(percent) FROM {$table}
             WHERE active = 1 AND product_id = %d
             AND (date_from IS NULL OR date_from <= %s)
             AND (date_to   IS NULL OR date_to   >= %s)",
            $product_id,
            $today,
            $today
        ));
        return is_numeric($pct) ? (float) $pct : 0.0;
    }

    private static function resolve_nfs_excluded($product_id, $parent_id) {
        global $wpdb;
        $candidates = array(
            $wpdb->prefix . 'aieo_dmm_no_free_shipping',
            $wpdb->prefix . 'om_no_free_shipping',
        );
        $check_ids = array($product_id);
        if ($parent_id > 0) { $check_ids[] = $parent_id; }
        foreach ($candidates as $table) {
            if (!self::table_exists($table)) { continue; }
            $placeholders = implode(',', array_fill(0, count($check_ids), '%d'));
            
            $found = (int) $wpdb->get_var($wpdb->prepare(
                "SELECT COUNT(*) FROM {$table} WHERE product_id IN ({$placeholders})",
                $check_ids
            ));
            
            if ($found > 0) { return true; }
        }
        return false;
    }

    
    private static function resolve_gift_offer_ids(array $brand_term_ids, array $cat_term_ids) {
        global $wpdb;
        $table = $wpdb->prefix . 'aieo_dmm_brand_gift_offers';
        if (!self::table_exists($table)) { return array(); }
        $today = current_time('Y-m-d');
        
        
        
        $rows = $wpdb->get_results($wpdb->prepare(
            "SELECT id, brand_term_ids, category_term_ids, need_term_ids, rule_operator FROM {$table}
             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) || empty($rows)) { return array(); }

        
        $need_term_ids = array();
        
        
        
        
        
        
        
        

        $out = array();
        foreach ($rows as $row) {
            $offer_brands = json_decode((string) ($row['brand_term_ids']    ?? '[]'), true);
            $offer_cats   = json_decode((string) ($row['category_term_ids'] ?? '[]'), true);
            $offer_needs  = json_decode((string) ($row['need_term_ids']     ?? '[]'), true);
            if (!is_array($offer_brands)) { $offer_brands = array(); }
            if (!is_array($offer_cats))   { $offer_cats   = array(); }
            if (!is_array($offer_needs))  { $offer_needs  = array(); }
            $op = (!empty($row['rule_operator']) && strtoupper($row['rule_operator']) === 'OR') ? 'OR' : 'AND';

            
            if (empty($offer_brands) && empty($offer_cats) && empty($offer_needs)) {
                $out[] = (int) $row['id'];
                continue;
            }

            if ($op === 'OR') {
                
                
                $match = (!empty($offer_brands) && !empty($brand_term_ids) && array_intersect($brand_term_ids, $offer_brands))
                      || (!empty($offer_cats)   && !empty($cat_term_ids)   && array_intersect($cat_term_ids,   $offer_cats))
                      || (!empty($offer_needs)  && !empty($need_term_ids)  && array_intersect($need_term_ids,  $offer_needs));
            } else {
                
                $brand_match = empty($offer_brands) || array_intersect($brand_term_ids, $offer_brands);
                $cat_match   = empty($offer_cats)   || array_intersect($cat_term_ids,   $offer_cats);
                $need_match  = empty($offer_needs)  || array_intersect($need_term_ids,  $offer_needs);
                $match = $brand_match && $cat_match && $need_match;
            }

            if ($match) {
                $out[] = (int) $row['id'];
            }
        }
        return $out;
    }

    private static function get_term_ids($product_id, $taxonomy) {
        $terms = wp_get_object_terms($product_id, $taxonomy, array('fields' => 'ids'));
        if (is_wp_error($terms) || !is_array($terms) || empty($terms)) {
            $parent = (int) wp_get_post_parent_id($product_id);
            if ($parent > 0) {
                $terms = wp_get_object_terms($parent, $taxonomy, array('fields' => 'ids'));
            }
        }
        return is_array($terms) ? array_map('intval', $terms) : array();
    }

    
    private static function current_version_key() {
        $domains = array('brands', 'gifts', 'loyalty', 'prices', 'needs', 'shipping');
        $parts = array();
        foreach ($domains as $d) {
            $parts[] = (int) get_option('aieo_dmm_cache_v_' . $d, 1);
        }
        return implode(':', $parts);
    }

    private static function hydrate_row($row) {
        if (!is_array($row)) { return null; }
        $row['product_id']              = (int) ($row['product_id'] ?? 0);
        $row['parent_id']               = (int) ($row['parent_id'] ?? 0);
        $row['base_regular']            = (float) ($row['base_regular'] ?? 0);
        $row['base_sale']               = (float) ($row['base_sale'] ?? 0);
        $row['effective_brand_pct']     = (float) ($row['effective_brand_pct'] ?? 0);
        $row['effective_cat_pct']       = (float) ($row['effective_cat_pct'] ?? 0);
        $row['effective_combined_pct']  = (float) ($row['effective_combined_pct'] ?? 0);
        $row['active_schedule_pct']     = (float) ($row['active_schedule_pct'] ?? 0);
        $row['nfs_excluded']            = !empty($row['nfs_excluded']);
        $row['brand_term_ids']          = self::decode_int_list($row['brand_term_ids'] ?? '');
        $row['cat_term_ids']            = self::decode_int_list($row['cat_term_ids'] ?? '');
        $row['eligible_gift_offer_ids'] = self::decode_int_list($row['eligible_gift_offer_ids'] ?? '');
        return $row;
    }

    private static function decode_int_list($raw) {
        if (is_array($raw)) { return array_map('intval', $raw); }
        if (!is_string($raw) || $raw === '') { return array(); }
        $decoded = json_decode($raw, true);
        return is_array($decoded) ? array_map('intval', $decoded) : array();
    }

    private static function table_exists($table) {
        static $memo = array();
        if (isset($memo[$table])) { return $memo[$table]; }
        global $wpdb;
        $found = $wpdb->get_var($wpdb->prepare(
            "SELECT COUNT(*) FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME = %s",
            $table
        ));
        return $memo[$table] = ((int) $found) > 0;
    }
}
