<?php

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

class AIEO_Newsletter_Registry {

    
    const OPTION = 'aieo_newsletter_settings';

    
    private static $instance = null;

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

    
    public function catalogue(): array {
        return array(
            ''         => array('class' => '',                                   'label' => __('— None (CSV export only) —', 'ai-eshop-optimizer')),
            'tnp'      => array('class' => 'AIEO_Newsletter_Adapter_TNP',        'label' => __('The Newsletter Plugin (TNP)', 'ai-eshop-optimizer')),
            'mailchimp'=> array('class' => 'AIEO_Newsletter_Adapter_Mailchimp',  'label' => 'Mailchimp'),
            'klaviyo'  => array('class' => 'AIEO_Newsletter_Adapter_Klaviyo',    'label' => 'Klaviyo'),
            'webhook'  => array('class' => 'AIEO_Newsletter_Adapter_Webhook',    'label' => __('Webhook (custom / iPaaS)', 'ai-eshop-optimizer')),
        );
    }

    
    public function get_settings(): array {
        $stored = get_option(self::OPTION, array());
        if (!is_array($stored)) { $stored = array(); }
        return array_merge(array(
            'provider'  => '',
            'tnp'       => array('client_key' => '', 'client_secret' => '', 'auto_create_lists' => '1', 'list_status' => 'private', 'list_name_prefix' => 'AIEO: ', 'status' => 'confirmed'),
            'mailchimp' => array('api_key' => '', 'list_id' => ''),
            'klaviyo'   => array('api_key' => '', 'list_id' => ''),
            'webhook'   => array('webhook_url' => '', 'shared_secret' => '', 'batch_size' => 500),
        ), $stored);
    }

    public function save_settings(array $patch) {
        $cur = $this->get_settings();
        if (isset($patch['provider'])) {
            $cat = $this->catalogue();
            $p = sanitize_key((string) $patch['provider']);
            $cur['provider'] = isset($cat[$p]) ? $p : '';
        }
        foreach (array('tnp', 'mailchimp', 'klaviyo', 'webhook') as $slug) {
            if (!isset($patch[$slug]) || !is_array($patch[$slug])) { continue; }
            foreach ($patch[$slug] as $k => $v) {
                $cur[$slug][sanitize_key((string) $k)] = is_string($v) ? sanitize_text_field($v) : $v;
            }
        }
        update_option(self::OPTION, $cur, false);
        return $cur;
    }

    
    public function adapter(): ?AIEO_Newsletter_Adapter_Base {
        $s = $this->get_settings();
        $provider = (string) $s['provider'];
        if ($provider === '') { return null; }
        $cat = $this->catalogue();
        if (!isset($cat[$provider])) { return null; }
        $class = (string) $cat[$provider]['class'];
        if ($class === '' || !class_exists($class)) { return null; }
        $provider_settings = is_array($s[$provider] ?? null) ? $s[$provider] : array();
        return new $class($provider_settings);
    }

    
    public function sync_cohort(string $cohort, array $filter = array()): array {
        global $wpdb;

        
        
        
        if (class_exists('AIEO_DMM_Web_Push') && !\AIEO_DMM_Web_Push::is_engine_live()) {
            return array('ok' => false, 'error' => 'engine_paused', 'synced' => 0, 'failed' => 0);
        }

        $adapter = $this->adapter();
        if ($adapter === null) {
            return array('ok' => false, 'error' => 'no-provider-configured');
        }

        $tbl_ci  = $wpdb->prefix . 'aieo_customer_intelligence';
        $tbl_log = $wpdb->prefix . 'aieo_newsletter_sync_log';

        
        $wpdb->insert($tbl_log, array(
            'provider'             => $adapter->get_id(),
            'cohort'               => $cohort,
            'audience_filter_json' => wp_json_encode($filter),
            'status'               => 'running',
            'triggered_by'         => (int) get_current_user_id(),
        ));
        $sync_id = (int) $wpdb->insert_id;

        try {
            $contacts = $this->load_audience($tbl_ci, $cohort, $filter);
            $audience_count = count($contacts);
            $wpdb->update($tbl_log, array('audience_count' => $audience_count), array('sync_id' => $sync_id));

            $result = $adapter->sync_contacts($contacts, $cohort);
            $wpdb->update($tbl_log, array(
                'synced_count'        => (int) ($result['synced'] ?? 0),
                'failed_count'        => (int) ($result['failed'] ?? 0),
                'status'              => ($result['ok'] ?? false) ? 'completed' : 'failed',
                'error_text'          => substr((string) ($result['error'] ?? ''), 0, 500),
                'provider_segment_id' => substr((string) ($result['provider_segment_id'] ?? ''), 0, 100),
                'completed_at'        => current_time('mysql', true),
            ), array('sync_id' => $sync_id));

            return array_merge($result, array('sync_id' => $sync_id, 'audience_count' => $audience_count));
        } catch (\Throwable $e) {
            $wpdb->update($tbl_log, array(
                'status'       => 'failed',
                'error_text'   => substr($e->getMessage(), 0, 500),
                'completed_at' => current_time('mysql', true),
            ), array('sync_id' => $sync_id));
            return array('ok' => false, 'error' => $e->getMessage(), 'sync_id' => $sync_id);
        }
    }

    
    private function load_audience(string $tbl_ci, string $cohort, array $filter): array {
        global $wpdb;
        $vitals = $wpdb->prefix . 'aieo_core_product_vitals';

        
        
        
        
        
        
        
        
        
        
        
        
        
        $segment_cohorts = array('vip', 'loyalist', 'brand_devoted', 'replenisher', 'newbie', 'discount_hunter');

        if ($cohort === 'pure_intent') {
            $where = " WHERE ci.sole_order_share >= 0.50 ";
            $args  = array();
        } elseif (in_array($cohort, $segment_cohorts, true)) {
            $where = " WHERE JSON_SEARCH(IFNULL(ci.segments_json, '[]'), 'one', %s) IS NOT NULL ";
            $args  = array($cohort);
        } else {
            $where = " WHERE ci.dormancy_cohort = %s ";
            $args  = array($cohort);
        }

        if (!empty($filter['only_email'])) {
            $where .= " AND ci.email <> '' ";
        }
        if (isset($filter['min_score']) && (int) $filter['min_score'] > 0) {
            $where .= " AND ci.reactivation_score >= %d ";
            $args[] = (int) $filter['min_score'];
        }
        if (isset($filter['min_ltv']) && (float) $filter['min_ltv'] > 0) {
            $where .= " AND ci.ltv_total >= %f ";
            $args[] = (float) $filter['min_ltv'];
        }
        if (isset($filter['min_confidence']) && (float) $filter['min_confidence'] > 0) {
            $where .= " AND ci.inferred_priorities_confidence >= %f ";
            $args[] = (float) $filter['min_confidence'];
        }
        if (!empty($filter['inferred_priority'])) {
            $where .= " AND ci.inferred_top_priority = %s ";
            $args[] = (string) $filter['inferred_priority'];
        }

        $sql = "SELECT ci.eponymous_id, ci.wp_user_id, ci.email,
                       ci.ltv_total AS ltv, ci.orders_count, ci.recency_days,
                       ci.top_brand_id, ci.top_category_id, ci.reactivation_score,
                       ci.dormancy_cohort,
                       ci.discount_share, ci.price_band, ci.sole_order_share,
                       ci.inferred_top_priority, ci.inferred_priorities_confidence,
                       ci.segments_json,
                       ci.brand_affinity_json
                FROM {$tbl_ci} ci
                {$where}
                AND ci.email <> ''
                ORDER BY ci.ltv_total DESC";

        
        $sql .= ' LIMIT 50000';

        $rows = $wpdb->get_results($wpdb->prepare($sql, ...$args), ARRAY_A);

        
        $brands = array();
        $cats   = array();
        $name_brand = function ($id) use (&$brands, $wpdb, $vitals) {
            $id = (int) $id;
            if ($id <= 0) { return ''; }
            if (!isset($brands[$id])) {
                $brands[$id] = (string) $wpdb->get_var($wpdb->prepare(
                    "SELECT brand FROM {$vitals} WHERE brand_id = %d AND brand <> '' LIMIT 1",
                    $id
                ));
            }
            return $brands[$id];
        };
        $name_cat = function ($id) use (&$cats, $wpdb, $vitals) {
            $id = (int) $id;
            if ($id <= 0) { return ''; }
            if (!isset($cats[$id])) {
                $cats[$id] = (string) $wpdb->get_var($wpdb->prepare(
                    "SELECT head_category FROM {$vitals} WHERE head_id = %d AND head_category <> '' LIMIT 1",
                    $id
                ));
            }
            return $cats[$id];
        };

        
        
        
        
        $tbl_wl = $wpdb->prefix . 'aieo_wishlist';
        $user_ids = array();
        foreach ((array) $rows as $r) {
            $uid = (int) ($r['wp_user_id'] ?? 0);
            if ($uid > 0) { $user_ids[$uid] = true; }
        }
        $wishlist_brands_by_user = array();
        if (!empty($user_ids)) {
            $uid_list = array_keys($user_ids);
            $placeholders = implode(',', array_fill(0, count($uid_list), '%d'));
            
            $wl_rows = $wpdb->get_results($wpdb->prepare(
                "SELECT user_id, item_id FROM {$tbl_wl}
                  WHERE item_type = 'brand' AND user_id IN ({$placeholders})
                  ORDER BY user_id, date_added DESC",
                $uid_list
            ), ARRAY_A);
            foreach ((array) $wl_rows as $wr) {
                $uid = (int) $wr['user_id'];
                if (!isset($wishlist_brands_by_user[$uid])) {
                    $wishlist_brands_by_user[$uid] = array();
                }
                $wishlist_brands_by_user[$uid][] = (int) $wr['item_id'];
            }
        }

        $out = array();
        foreach ((array) $rows as $r) {
            
            
            $segments = array();
            if (!empty($r['segments_json'])) {
                $decoded = json_decode((string) $r['segments_json'], true);
                if (is_array($decoded)) { $segments = $decoded; }
            }
            $segments_set = array_flip($segments);

            
            
            
            
            
            
            
            $row_uid           = (int) ($r['wp_user_id'] ?? 0);
            $wishlisted_bids   = $row_uid > 0 ? ($wishlist_brands_by_user[$row_uid] ?? array()) : array();

            $derived_bids = array();
            if (!empty($r['brand_affinity_json'])) {
                $aff = json_decode((string) $r['brand_affinity_json'], true);
                if (is_array($aff)) {
                    arsort($aff, SORT_NUMERIC);
                    $derived_bids = array_map('intval', array_keys($aff));
                }
            }

            $unified_bids = array();
            $seen_b       = array();
            foreach (array_merge($wishlisted_bids, $derived_bids) as $bid) {
                $bid = (int) $bid;
                if ($bid <= 0 || isset($seen_b[$bid])) { continue; }
                $seen_b[$bid] = true;
                $unified_bids[] = $bid;
                if (count($unified_bids) >= 5) { break; }
            }
            $unified_brand_names = array_values(array_filter(array_map($name_brand, $unified_bids)));

            $out[] = array(
                'email'                  => (string) $r['email'],
                'eponymous_id'           => (int) $r['eponymous_id'],
                'wp_user_id'             => (int) $r['wp_user_id'],
                'ltv'                    => (float) $r['ltv'],
                'orders_count'           => (int) $r['orders_count'],
                'recency_days'           => (int) $r['recency_days'],
                'top_brand'              => $name_brand($r['top_brand_id']),
                'top_category'           => $name_cat($r['top_category_id']),
                'reactivation_score'     => (int) $r['reactivation_score'],
                'dormancy_cohort'        => (string) $r['dormancy_cohort'],
                
                'discount_share'         => (float) ($r['discount_share'] ?? 0),
                'price_band'             => (int)   ($r['price_band']     ?? 0),
                'is_discount_hunter'     => isset($segments_set['discount_hunter']) ? 1 : 0,
                
                'sole_order_share'       => (float) ($r['sole_order_share'] ?? 0),
                'is_pure_intent'         => ((float) ($r['sole_order_share'] ?? 0)) >= 0.5 ? 1 : 0,
                
                'inferred_priority'      => (string) ($r['inferred_top_priority'] ?? ''),
                'inferred_confidence'    => (float)  ($r['inferred_priorities_confidence'] ?? 0),
                
                'segments'               => $segments,
                
                
                
                
                'top_brands'             => $unified_brand_names,
                'top_brand_ids'          => $unified_bids,
                'wishlisted_brand_ids'   => array_values($wishlisted_bids),
            );
        }
        return $out;
    }
}
