<?php

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

class AIEO_DMM_Loyalty_Classes extends AIEO_DMM_Module_Base {

    public function get_id() { return 'loyalty_classes'; }
    public function get_label() { return __('Customer Discounts', 'ai-eshop-optimizer'); }
    public function get_priority() { return 55; }
    public function get_group() { return 'special_pricing_offers'; }

    public function register_hooks() {
        add_action('wp_ajax_aieo_dmm_loyalty_class_save', array($this, 'ajax_save_class'));
        add_action('wp_ajax_aieo_dmm_loyalty_class_delete', array($this, 'ajax_delete_class'));
        add_action('wp_ajax_aieo_dmm_loyalty_assign_user', array($this, 'ajax_assign_user'));
        add_action('wp_ajax_aieo_dmm_loyalty_unassign_user', array($this, 'ajax_unassign_user'));
        add_action('wp_ajax_aieo_dmm_loyalty_bulk_upload', array($this, 'ajax_bulk_upload'));
        add_action('wp_ajax_aieo_dmm_loyalty_bulk_process', array($this, 'ajax_bulk_process'));
        add_action('wp_ajax_aieo_dmm_loyalty_search_users', array($this, 'ajax_search_users'));
        add_action('wp_ajax_aieo_dmm_loyalty_points_adjust', array($this, 'ajax_points_adjust'));

        
        add_action('show_user_profile', array($this, 'render_user_profile_field'));
        add_action('edit_user_profile', array($this, 'render_user_profile_field'));
        add_action('personal_options_update', array($this, 'save_user_profile_field'));
        add_action('edit_user_profile_update', array($this, 'save_user_profile_field'));

        
        
        
        add_action('woocommerce_order_status_processing', array($this, 'award_points_for_order'), 20, 1);
        add_action('woocommerce_order_status_completed',  array($this, 'award_points_for_order'), 20, 1);
    }

    public function render_subtab() {
        $this->render_template('loyalty-classes.php', array(
            'classes' => $this->fetch_classes(),
            'assignments_sample' => $this->fetch_recent_assignments(25),
        ));
    }

    
    public function fetch_classes() {
        global $wpdb;
        $table = $wpdb->prefix . 'aieo_dmm_loyalty_classes';
        if (!aieo_dmm_table_exists($table)) {
            return array();
        }
        
        $rows = $wpdb->get_results("SELECT * FROM {$table} ORDER BY enabled DESC, label ASC", ARRAY_A);
        return is_array($rows) ? $rows : array();
    }

    
    public function fetch_recent_assignments($limit = 25) {
        global $wpdb;
        $table = $wpdb->prefix . 'aieo_dmm_loyalty_assignments';
        $defs  = $wpdb->prefix . 'aieo_dmm_loyalty_classes';
        if (!aieo_dmm_table_exists($table) || !aieo_dmm_table_exists($defs)) {
            return array();
        }
        
        $rows = $wpdb->get_results($wpdb->prepare(
            "SELECT a.user_id, a.class_id, a.assigned_at, d.slug, d.label, d.extra_percent
             FROM {$table} a INNER JOIN {$defs} d ON d.id = a.class_id
             ORDER BY a.assigned_at DESC LIMIT %d",
            (int) $limit
        ), ARRAY_A);
        if (!is_array($rows)) {
            return array();
        }
        foreach ($rows as &$row) {
            $user = get_userdata((int) $row['user_id']);
            $row['user_label'] = $user ? ($user->display_name . ' <' . $user->user_email . '>') : ('#' . $row['user_id']);
        }
        return $rows;
    }

    public function ajax_save_class() {
        AIEO_DMM::verify_ajax_request();

        global $wpdb;
        $table = $wpdb->prefix . 'aieo_dmm_loyalty_classes';
        if (!aieo_dmm_table_exists($table)) {
            wp_send_json_error(array('message' => __('Table missing.', 'ai-eshop-optimizer')));
        }

        $id    = isset($_POST['id']) ? absint(wp_unslash($_POST['id'])) : 0;
        $slug  = isset($_POST['slug']) ? sanitize_key(wp_unslash($_POST['slug'])) : '';
        $label = isset($_POST['label']) ? sanitize_text_field(wp_unslash($_POST['label'])) : '';
        $pct   = isset($_POST['extra_percent']) ? (float) $_POST['extra_percent'] : 0.0;
        $ppc   = isset($_POST['points_per_currency']) ? (float) $_POST['points_per_currency'] : 0.0;
        $enabled = !empty($_POST['enabled']) ? 1 : 0;
        $desc  = isset($_POST['description']) ? sanitize_textarea_field(wp_unslash($_POST['description'])) : '';

        if ($slug === '' || $label === '') {
            wp_send_json_error(array('message' => __('Slug and label are required.', 'ai-eshop-optimizer')));
        }
        if ($pct < 0 || $pct >= 100) {
            wp_send_json_error(array('message' => __('Percent must be between 0 and 100.', 'ai-eshop-optimizer')));
        }
        if ($ppc < 0) {
            wp_send_json_error(array('message' => __('Points per currency cannot be negative.', 'ai-eshop-optimizer')));
        }

        $data = array(
            'slug'                => $slug,
            'label'               => $label,
            'extra_percent'       => $pct,
            'points_per_currency' => $ppc,
            'enabled'             => $enabled,
            'description'         => $desc,
        );
        $formats = array('%s', '%s', '%f', '%f', '%d', '%s');

        if ($id > 0) {
            $wpdb->update($table, $data, array('id' => $id), $formats, array('%d'));
        } else {
            $existing = $wpdb->get_var($wpdb->prepare(
                "SELECT id FROM {$table} WHERE slug = %s",
                $slug
            ));
            if ($existing) {
                wp_send_json_error(array('message' => __('A class with that slug already exists.', 'ai-eshop-optimizer')));
            }
            $wpdb->insert($table, $data, $formats);
            $id = (int) $wpdb->insert_id;
        }
        AIEO_DMM_Cache::bump_version('loyalty');
        wp_send_json_success(array('id' => $id, 'message' => __('Class saved.', 'ai-eshop-optimizer')));
    }

    public function ajax_delete_class() {
        AIEO_DMM::verify_ajax_request();

        $id = isset($_POST['id']) ? absint(wp_unslash($_POST['id'])) : 0;
        if ($id <= 0) {
            wp_send_json_error(array('message' => __('Invalid id.', 'ai-eshop-optimizer')));
        }
        global $wpdb;
        $wpdb->delete($wpdb->prefix . 'aieo_dmm_loyalty_classes', array('id' => $id), array('%d'));
        $wpdb->delete($wpdb->prefix . 'aieo_dmm_loyalty_assignments', array('class_id' => $id), array('%d'));
        AIEO_DMM_Cache::bump_version('loyalty');
        wp_send_json_success();
    }

    public function ajax_assign_user() {
        AIEO_DMM::verify_ajax_request();

        $user_id = isset($_POST['user_id']) ? absint(wp_unslash($_POST['user_id'])) : 0;
        $class_id = isset($_POST['class_id']) ? absint(wp_unslash($_POST['class_id'])) : 0;
        if ($user_id <= 0 || $class_id <= 0) {
            wp_send_json_error(array('message' => __('Pick a user and class.', 'ai-eshop-optimizer')));
        }
        if (!get_userdata($user_id)) {
            wp_send_json_error(array('message' => __('User not found.', 'ai-eshop-optimizer')));
        }
        global $wpdb;
        $table = $wpdb->prefix . 'aieo_dmm_loyalty_assignments';
        $wpdb->query($wpdb->prepare(
            
            "INSERT IGNORE INTO {$table} (user_id, class_id) VALUES (%d, %d)",
            $user_id,
            $class_id
        ));
        AIEO_DMM_Cache::bump_version('loyalty');
        do_action('aieo_dmm_loyalty_assignment_saved', $user_id, $class_id);
        wp_send_json_success();
    }

    public function ajax_unassign_user() {
        AIEO_DMM::verify_ajax_request();

        $user_id = isset($_POST['user_id']) ? absint(wp_unslash($_POST['user_id'])) : 0;
        $class_id = isset($_POST['class_id']) ? absint(wp_unslash($_POST['class_id'])) : 0;
        if ($user_id <= 0 || $class_id <= 0) {
            wp_send_json_error(array('message' => __('Invalid input.', 'ai-eshop-optimizer')));
        }
        global $wpdb;
        $wpdb->delete($wpdb->prefix . 'aieo_dmm_loyalty_assignments', array(
            'user_id' => $user_id,
            'class_id' => $class_id,
        ), array('%d', '%d'));
        AIEO_DMM_Cache::bump_version('loyalty');
        do_action('aieo_dmm_loyalty_assignment_deleted', $user_id, $class_id);
        wp_send_json_success();
    }

    public function ajax_bulk_upload() {
        AIEO_DMM::verify_ajax_request();

        
        if (empty($_FILES['csv_file']['tmp_name']) || !is_uploaded_file($_FILES['csv_file']['tmp_name'])) {
            wp_send_json_error(array('message' => __('No file uploaded.', 'ai-eshop-optimizer')));
        }
        $handle = fopen($_FILES['csv_file']['tmp_name'], 'r');
        
        if (!$handle) {
            wp_send_json_error(array('message' => __('Cannot read file.', 'ai-eshop-optimizer')));
        }
        $header = fgetcsv($handle);
        if (!$header) {
            fclose($handle);
            wp_send_json_error(array('message' => __('Empty CSV.', 'ai-eshop-optimizer')));
        }
        $map = array();
        foreach ($header as $i => $c) {
            $map[strtolower(trim((string) $c))] = $i;
        }
        
        if (!isset($map['class_slug']) || !(isset($map['user_email']) || isset($map['user_login']) || isset($map['user_id']))) {
            fclose($handle);
            wp_send_json_error(array('message' => __('CSV must contain class_slug and one of user_email/user_login/user_id.', 'ai-eshop-optimizer')));
        }

        $rows = array();
        while (($row = fgetcsv($handle)) !== false) {
            $rows[] = $row;
        }
        fclose($handle);

        if (empty($rows)) {
            wp_send_json_error(array('message' => __('No rows in CSV.', 'ai-eshop-optimizer')));
        }

        $job_id = wp_generate_password(16, false, false);
        $this->create_job($job_id, 'loyalty_bulk_assign', count($rows), array(
            'map'  => $map,
            'rows' => $rows,
        ));
        wp_send_json_success(array('job_id' => $job_id, 'total' => count($rows)));
    }

    public function ajax_bulk_process() {
        AIEO_DMM::verify_ajax_request();

        $job_id = isset($_POST['job_id']) ? sanitize_text_field(wp_unslash($_POST['job_id'])) : '';
        $job = $this->load_job($job_id);
        if (!$job || $job['type'] !== 'loyalty_bulk_assign') {
            wp_send_json_error(array('message' => __('Invalid job.', 'ai-eshop-optimizer')));
        }
        $params = json_decode($job['params'], true);
        if (!is_array($params)) {
            wp_send_json_error(array('message' => __('Corrupted job.', 'ai-eshop-optimizer')));
        }

        $batch_size = 100;
        $offset = (int) $job['processed'];
        $slice = array_slice($params['rows'], $offset, $batch_size);

        global $wpdb;
        $defs = $wpdb->prefix . 'aieo_dmm_loyalty_classes';
        $assign = $wpdb->prefix . 'aieo_dmm_loyalty_assignments';

        $errors = array();
        foreach ($slice as $row) {
            $slug = isset($params['map']['class_slug']) && isset($row[$params['map']['class_slug']])
                ? sanitize_key($row[$params['map']['class_slug']])
                : '';
            if ($slug === '') {
                $errors[] = __('Missing class_slug on a row.', 'ai-eshop-optimizer');
                continue;
            }
            $class_id = (int) $wpdb->get_var($wpdb->prepare(
                "SELECT id FROM {$defs} WHERE slug = %s",
                $slug
            ));
            if ($class_id <= 0) {
                $errors[] = sprintf( __('Class %s not found.', 'ai-eshop-optimizer'), $slug);
                continue;
            }
            $user = $this->resolve_user_from_row($row, $params['map']);
            if (!$user) {
                $errors[] = __('User not found for a row.', 'ai-eshop-optimizer');
                continue;
            }
            $wpdb->query($wpdb->prepare(
                
                "INSERT IGNORE INTO {$assign} (user_id, class_id) VALUES (%d, %d)",
                $user->ID,
                $class_id
            ));
        }
        $new_processed = $offset + count($slice);
        $complete = $new_processed >= (int) $job['total'];
        $this->update_job($job_id, array(
            'processed' => $new_processed,
            'status'    => $complete ? 'complete' : 'running',
        ));
        if ($complete) {
            AIEO_DMM_Cache::bump_version('loyalty');
        }
        wp_send_json_success(array(
            'processed' => $new_processed,
            'total'     => (int) $job['total'],
            'complete'  => $complete,
            'percentage'=> (int) $job['total'] > 0 ? (int) floor(($new_processed / (int) $job['total']) * 100) : 100,
            'errors'    => array_slice($errors, 0, 20),
        ));
    }

    private function resolve_user_from_row(array $row, array $map) {
        if (isset($map['user_id']) && !empty($row[$map['user_id']])) {
            $u = get_user_by('id', (int) $row[$map['user_id']]);
            if ($u) return $u;
        }
        if (isset($map['user_email']) && !empty($row[$map['user_email']])) {
            $u = get_user_by('email', sanitize_email($row[$map['user_email']]));
            if ($u) return $u;
        }
        if (isset($map['user_login']) && !empty($row[$map['user_login']])) {
            $u = get_user_by('login', sanitize_user($row[$map['user_login']], true));
            if ($u) return $u;
        }
        return null;
    }

    public function ajax_search_users() {
        AIEO_DMM::verify_ajax_request();

        $q = isset($_GET['q']) ? sanitize_text_field(wp_unslash($_GET['q'])) : '';
        $users = get_users(array(
            'search' => '*' . $q . '*',
            'search_columns' => array('user_login', 'user_email', 'display_name'),
            'number' => 25,
            'orderby' => 'display_name',
        ));
        $out = array();
        foreach ($users as $u) {
            $out[] = array(
                'id' => (int) $u->ID,
                'text' => $u->display_name . ' <' . $u->user_email . '> (#' . $u->ID . ')',
            );
        }
        wp_send_json(array('results' => $out));
    }

    public function render_user_profile_field($user) {
        if (!current_user_can(AIEO_CAPABILITY)) {
            return;
        }
        $classes = $this->fetch_classes();
        if (empty($classes)) {
            return;
        }
        $assigned = $this->get_class_ids_for_user((int) $user->ID);
        $balance  = self::get_balance((int) $user->ID);
        echo '<h2>' . esc_html__('AI eShop Loyalty Classes', 'ai-eshop-optimizer') . '</h2>';
        wp_nonce_field('aieo_dmm_user_loyalty', 'aieo_dmm_user_loyalty_nonce');
        echo '<table class="form-table">';
        echo '<tr><th>' . esc_html__('Classes', 'ai-eshop-optimizer') . '</th><td>';
        foreach ($classes as $class) {
            $checked = in_array((int) $class['id'], $assigned, true) ? 'checked' : '';
            printf(
                '<label style="display:block"><input type="checkbox" name="aieo_dmm_loyalty_classes[]" value="%d" %s> %s — %s%% off, %s pts/unit</label>',
                (int) $class['id'],
                esc_attr($checked),
                esc_html($class['label']),
                esc_html((float) $class['extra_percent']),
                esc_html(number_format((float) (isset($class['points_per_currency']) ? $class['points_per_currency'] : 0), 4))
            );
        }
        echo '</td></tr>';
        echo '<tr><th>' . esc_html__('Points balance', 'ai-eshop-optimizer') . '</th><td><strong>' . esc_html(number_format($balance, 2)) . '</strong></td></tr>';
        echo '</table>';
    }

    public function save_user_profile_field($user_id) {
        if (!current_user_can(AIEO_CAPABILITY)) {
            return;
        }
        if (empty($_POST['aieo_dmm_user_loyalty_nonce'])
            || !wp_verify_nonce(sanitize_text_field(wp_unslash($_POST['aieo_dmm_user_loyalty_nonce'])), 'aieo_dmm_user_loyalty')) {
            return;
        }
        $selected = isset($_POST['aieo_dmm_loyalty_classes']) && is_array($_POST['aieo_dmm_loyalty_classes'])
            ? array_map('absint', wp_unslash($_POST['aieo_dmm_loyalty_classes']))
            : array();

        global $wpdb;
        $table = $wpdb->prefix . 'aieo_dmm_loyalty_assignments';
        $wpdb->delete($table, array('user_id' => (int) $user_id), array('%d'));
        foreach ($selected as $cid) {
            $wpdb->insert($table, array('user_id' => $user_id, 'class_id' => $cid), array('%d', '%d'));
        }
        AIEO_DMM_Cache::bump_version('loyalty');
    }

    
    private function get_class_ids_for_user($user_id) {
        global $wpdb;
        $table = $wpdb->prefix . 'aieo_dmm_loyalty_assignments';
        if (!aieo_dmm_table_exists($table)) {
            return array();
        }
        
        $ids = $wpdb->get_col($wpdb->prepare(
            "SELECT class_id FROM {$table} WHERE user_id = %d",
            $user_id
        ));
        return is_array($ids) ? array_map('intval', $ids) : array();
    }

    
    private function create_job($job_id, $type, $total, array $params) {
        global $wpdb;
        $table = $wpdb->prefix . 'aieo_dmm_export_jobs';
        $wpdb->insert($table, array(
            'job_id'    => $job_id,
            'type'      => $type,
            'status'    => 'running',
            'total'     => $total,
            'processed' => 0,
            'params'    => wp_json_encode($params),
            'user_id'   => get_current_user_id(),
        ), array('%s', '%s', '%s', '%d', '%d', '%s', '%d'));
    }
    private function load_job($job_id) {
        global $wpdb;
        $table = $wpdb->prefix . 'aieo_dmm_export_jobs';
        return $wpdb->get_row($wpdb->prepare(
            "SELECT * FROM {$table} WHERE job_id = %s",
            $job_id
        ), ARRAY_A);
    }
    private function update_job($job_id, array $fields) {
        global $wpdb;
        $table = $wpdb->prefix . 'aieo_dmm_export_jobs';
        $formats = array();
        foreach ($fields as $k => $v) {
            $formats[] = in_array($k, array('processed', 'total', 'last_id', 'user_id'), true) ? '%d' : '%s';
        }
        $wpdb->update($table, $fields, array('job_id' => $job_id), $formats, array('%s'));
    }

    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    

    
    public static function get_balance($user_id) {
        global $wpdb;
        $user_id = (int) $user_id;
        if ($user_id <= 0) { return 0.0; }
        $table = $wpdb->prefix . 'aieo_dmm_loyalty_points';
        if (!aieo_dmm_table_exists($table)) { return 0.0; }
        
        $sum = $wpdb->get_var($wpdb->prepare("SELECT COALESCE(SUM(delta),0) FROM {$table} WHERE user_id = %d", $user_id));
        return (float) $sum;
    }

    
    public static function add_points($user_id, $delta, $source, $source_ref = null, $class_id = null, $notes = null) {
        global $wpdb;
        $user_id = (int) $user_id;
        $delta   = (float) $delta;
        if ($user_id <= 0 || $delta == 0.0) {
            return self::get_balance($user_id);
        }
        $table = $wpdb->prefix . 'aieo_dmm_loyalty_points';
        if (!aieo_dmm_table_exists($table)) {
            return 0.0;
        }

        
        
        
        if ($source_ref !== null && $source_ref !== '') {
            $exists = (int) $wpdb->get_var($wpdb->prepare(
                
                "SELECT id FROM {$table} WHERE source = %s AND source_ref = %s AND user_id = %d LIMIT 1",
                $source,
                (string) $source_ref,
                $user_id
            ));
            if ($exists > 0) {
                return self::get_balance($user_id);
            }
        }

        $new_balance = self::get_balance($user_id) + $delta;

        $wpdb->insert($table, array(
            'user_id'       => $user_id,
            'delta'         => $delta,
            'balance_after' => $new_balance,
            'source'        => (string) $source,
            'source_ref'    => $source_ref !== null ? (string) $source_ref : null,
            'class_id'      => $class_id ? (int) $class_id : null,
            'notes'         => $notes !== null ? substr((string) $notes, 0, 255) : null,
        ), array('%d', '%f', '%f', '%s', '%s', '%d', '%s'));

        
        do_action('aieo_dmm_loyalty_points_added', $user_id, $delta, $new_balance, (string) $source, $source_ref);

        return $new_balance;
    }

    
    public function award_points_for_order($order_id) {
        if (!function_exists('wc_get_order')) { return; }
        $order = wc_get_order($order_id);
        if (!$order) { return; }
        $user_id = (int) $order->get_user_id();
        if ($user_id <= 0) { return; }

        
        global $wpdb;
        $defs   = $wpdb->prefix . 'aieo_dmm_loyalty_classes';
        $assign = $wpdb->prefix . 'aieo_dmm_loyalty_assignments';
        if (!aieo_dmm_table_exists($defs) || !aieo_dmm_table_exists($assign)) {
            return;
        }
        
        $rate = (float) $wpdb->get_var($wpdb->prepare(
            "SELECT COALESCE(SUM(d.points_per_currency),0)
             FROM {$assign} a
             INNER JOIN {$defs} d ON d.id = a.class_id
             WHERE a.user_id = %d AND d.enabled = 1",
            $user_id
        ));
        if ($rate <= 0) {
            return;
        }

        $total = (float) $order->get_total();
        if ($total <= 0) {
            return;
        }

        $points = round($total * $rate, 2);

        
        
        $class_id = (int) $wpdb->get_var($wpdb->prepare(
            "SELECT d.id FROM {$assign} a
             INNER JOIN {$defs} d ON d.id = a.class_id
             WHERE a.user_id = %d AND d.enabled = 1
             ORDER BY d.points_per_currency DESC LIMIT 1",
            $user_id
        ));

        self::add_points(
            $user_id,
            $points,
            'order',
            'wc:' . (int) $order_id,
            $class_id ?: null,
            sprintf(
                
                __('Order #%1$d @ %2$s pts/unit', 'ai-eshop-optimizer'),
                (int) $order_id,
                number_format($rate, 4)
            )
        );
    }

    
    public function ajax_points_adjust() {
        AIEO_DMM::verify_ajax_request();

        $user_id = isset($_POST['user_id']) ? absint(wp_unslash($_POST['user_id'])) : 0;
        $delta   = isset($_POST['delta']) ? (float) sanitize_text_field(wp_unslash($_POST['delta'])) : 0.0;
        $notes   = isset($_POST['notes']) ? sanitize_text_field(wp_unslash($_POST['notes'])) : '';
        if ($user_id <= 0 || $delta == 0.0) {
            wp_send_json_error(array('message' => __('Provide a user and a non-zero delta.', 'ai-eshop-optimizer')));
        }

        
        
        $ref = 'manual:' . get_current_user_id() . ':' . time();
        $new_balance = self::add_points($user_id, $delta, 'manual', $ref, null, $notes !== '' ? $notes : null);

        wp_send_json_success(array(
            'user_id' => $user_id,
            'delta'   => $delta,
            'balance' => $new_balance,
            'message' => sprintf(
                
                __('Applied %1$+.2f pts. New balance: %2$s', 'ai-eshop-optimizer'),
                $delta,
                number_format($new_balance, 2)
            ),
        ));
    }
}
