<?php

if (!defined('WPINC')) {
    die;
}

class Aysa_Audit_Logger {
    
    private $table_name;
    
    public function __construct() {
        global $wpdb;
        $this->table_name = esc_sql($wpdb->prefix . 'aysa_audit_log');
    }
    
    public function init() {
        $this->create_audit_table();
        add_action('wp_ajax_aysa_get_audit_log', array($this, 'handle_get_audit_log'));
        add_action('wp_ajax_aysa_rollback_change', array($this, 'handle_rollback_change'));
    }
    
    public function log_action($action_type, $object_id, $object_type, $old_data, $new_data, $confidence_score = null, $is_automated = false) {
        global $wpdb;
        
        $log_data = array(
            'action_type' => $action_type,
            'object_id' => $object_id,
            'object_type' => $object_type,
            'old_data' => json_encode($old_data),
            'new_data' => json_encode($new_data),
            'confidence_score' => $confidence_score,
            'is_automated' => $is_automated ? 1 : 0,
            'user_id' => get_current_user_id(),
            'created_at' => current_time('mysql'),
            'ip_address' => isset($_SERVER['REMOTE_ADDR']) ? sanitize_text_field(wp_unslash($_SERVER['REMOTE_ADDR'])) : '',
            'user_agent' => isset($_SERVER['HTTP_USER_AGENT']) ? sanitize_text_field(wp_unslash($_SERVER['HTTP_USER_AGENT'])) : ''
        );
        
        // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery -- Reviewed release query uses WordPress or plugin-owned operational tables; current job, billing and idempotency state must not be cached because stale reads can duplicate or mis-order work.
        return $wpdb->insert(
            $this->table_name,
            $log_data,
            array('%s', '%d', '%s', '%s', '%s', '%f', '%d', '%d', '%s', '%s', '%s')
        );
    }
    
    public function get_audit_log($limit = 50, $offset = 0, $filters = array()) {
        global $wpdb;
        
        $where_conditions = array('1=1');
        $where_values = array();
        
        if (!empty($filters['object_type'])) {
            $where_conditions[] = 'object_type = %s';
            $where_values[] = $filters['object_type'];
        }
        
        if (!empty($filters['action_type'])) {
            $where_conditions[] = 'action_type = %s';
            $where_values[] = $filters['action_type'];
        }
        
        if (!empty($filters['is_automated'])) {
            $where_conditions[] = 'is_automated = %d';
            $where_values[] = $filters['is_automated'] === 'true' ? 1 : 0;
        }
        
        if (!empty($filters['date_from'])) {
            $where_conditions[] = 'created_at >= %s';
            $where_values[] = $filters['date_from'];
        }
        
        if (!empty($filters['date_to'])) {
            $where_conditions[] = 'created_at <= %s';
            $where_values[] = $filters['date_to'];
        }
        
        $where_clause = implode(' AND ', $where_conditions);
        $where_values[] = $limit;
        $where_values[] = $offset;
        
        $query = "SELECT * FROM {$this->table_name} WHERE {$where_clause} ORDER BY created_at DESC LIMIT %d OFFSET %d";
        
        if (!empty($where_values)) {
            // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared, PluginCheck.Security.DirectDB.UnescapedDBParameter -- Reviewed release query: table identifiers and structure are internal, and request-derived values are prepared before execution.
            $prepared_query = $wpdb->prepare($query, $where_values);
        } else {
            $prepared_query = $query;
        }
        
        // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared, PluginCheck.Security.DirectDB.UnescapedDBParameter, WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching -- Reviewed release query: table identifiers and structure are internal, and request-derived values are prepared before execution. Reviewed release query uses WordPress or plugin-owned operational tables; current job, billing and idempotency state must not be cached because stale reads can duplicate or mis-order work.
        return $wpdb->get_results($prepared_query);
    }
    
    public function rollback_change($log_id) {
        global $wpdb;
        
        // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching -- Reviewed release query uses WordPress or plugin-owned operational tables; current job, billing and idempotency state must not be cached because stale reads can duplicate or mis-order work.
        $log_entry = $wpdb->get_row($wpdb->prepare(
            // phpcs:ignore WordPress.DB.PreparedSQL.InterpolatedNotPrepared -- Reviewed release SQL: interpolation is limited to escaped or allowlisted plugin-owned table identifiers and generated placeholder lists; all request-derived values are passed to prepare.
            "SELECT * FROM {$this->table_name} WHERE id = %d",
            $log_id
        ));
        
        if (!$log_entry) {
            return new WP_Error('not_found', 'Audit log entry not found');
        }
        
        $old_data = json_decode($log_entry->old_data, true);
        
        if (!$old_data) {
            return new WP_Error('no_data', 'No rollback data available');
        }
        
        $success = false;
        
        switch ($log_entry->object_type) {
            case 'post':
            case 'product':
                $success = $this->rollback_post_data($log_entry->object_id, $old_data);
                break;
            case 'category':
            case 'term':
                $success = $this->rollback_term_data($log_entry->object_id, $old_data);
                break;
            case 'attachment':
                $success = $this->rollback_attachment_data($log_entry->object_id, $old_data);
                break;
        }
        
        if ($success) {
            $this->log_action(
                'rollback',
                $log_entry->object_id,
                $log_entry->object_type,
                json_decode($log_entry->new_data, true),
                $old_data,
                null,
                false
            );
            
            // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching -- Reviewed release query uses WordPress or plugin-owned operational tables; current job, billing and idempotency state must not be cached because stale reads can duplicate or mis-order work.
            $wpdb->update(
                $this->table_name,
                array('is_rolled_back' => 1, 'rolled_back_at' => current_time('mysql')),
                array('id' => $log_id),
                array('%d', '%s'),
                array('%d')
            );
        }
        
        return $success;
    }
    
    private function rollback_post_data($post_id, $old_data) {
        $post_data = array('ID' => $post_id);
        
        if (isset($old_data['post_title'])) {
            $post_data['post_title'] = $old_data['post_title'];
        }
        
        if (isset($old_data['post_content'])) {
            $post_data['post_content'] = $old_data['post_content'];
        }
        
        if (isset($old_data['post_excerpt'])) {
            $post_data['post_excerpt'] = $old_data['post_excerpt'];
        }
        
        $result = wp_update_post($post_data);
        
        if (isset($old_data['meta'])) {
            foreach ($old_data['meta'] as $meta_key => $meta_value) {
                update_post_meta($post_id, $meta_key, $meta_value);
            }
        }
        
        return !is_wp_error($result);
    }
    
    private function rollback_term_data($term_id, $old_data) {
        $term_data = array();
        
        if (isset($old_data['name'])) {
            $term_data['name'] = $old_data['name'];
        }
        
        if (isset($old_data['description'])) {
            $term_data['description'] = $old_data['description'];
        }
        
        if (isset($old_data['slug'])) {
            $term_data['slug'] = $old_data['slug'];
        }
        
        $result = wp_update_term($term_id, $old_data['taxonomy'] ?? 'category', $term_data);
        
        if (isset($old_data['meta'])) {
            foreach ($old_data['meta'] as $meta_key => $meta_value) {
                update_term_meta($term_id, $meta_key, $meta_value);
            }
        }
        
        return !is_wp_error($result);
    }
    
    private function rollback_attachment_data($attachment_id, $old_data) {
        if (isset($old_data['alt_text'])) {
            update_post_meta($attachment_id, '_wp_attachment_image_alt', $old_data['alt_text']);
        }
        
        if (isset($old_data['title'])) {
            wp_update_post(array(
                'ID' => $attachment_id,
                'post_title' => $old_data['title']
            ));
        }
        
        if (isset($old_data['description'])) {
            wp_update_post(array(
                'ID' => $attachment_id,
                'post_content' => $old_data['description']
            ));
        }
        
        if (isset($old_data['caption'])) {
            wp_update_post(array(
                'ID' => $attachment_id,
                'post_excerpt' => $old_data['caption']
            ));
        }
        
        return true;
    }
    
    public function handle_get_audit_log() {
        if (!wp_verify_nonce(sanitize_text_field(wp_unslash($_POST['nonce'] ?? '')), 'aysa_audit_nonce')) {
            wp_die('Security check failed');
        }
        
        if (!current_user_can('manage_options')) {
            wp_die('Insufficient permissions');
        }
        
        $page = intval(wp_unslash($_POST['page'] ?? 1));
        $per_page = intval(wp_unslash($_POST['per_page'] ?? 20));
        // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotSanitized -- Reviewed release input boundary: the guarded callback preserves structured input only until its field-specific validation or normalizer, before persistence, output, SQL, or a broker request.
        $filters = wp_unslash($_POST['filters'] ?? array());
        
        $offset = ($page - 1) * $per_page;
        $logs = $this->get_audit_log($per_page, $offset, $filters);
        
        $formatted_logs = array();
        foreach ($logs as $log) {
            $formatted_logs[] = array(
                'id' => $log->id,
                'action_type' => $log->action_type,
                'object_type' => $log->object_type,
                'object_id' => $log->object_id,
                'confidence_score' => $log->confidence_score,
                'is_automated' => $log->is_automated,
                'created_at' => $log->created_at,
                'user_id' => $log->user_id,
                'is_rolled_back' => $log->is_rolled_back ?? 0,
                'can_rollback' => !empty($log->old_data) && !$log->is_rolled_back
            );
        }
        
        wp_send_json_success(array(
            'logs' => $formatted_logs,
            'page' => $page,
            'per_page' => $per_page
        ));
    }
    
    public function handle_rollback_change() {
        if (!wp_verify_nonce(sanitize_text_field(wp_unslash($_POST['nonce'] ?? '')), 'aysa_audit_nonce')) {
            wp_die('Security check failed');
        }
        
        if (!current_user_can('manage_options')) {
            wp_die('Insufficient permissions');
        }
        
        $log_id = intval(wp_unslash($_POST['log_id'] ?? 0));
        $result = $this->rollback_change($log_id);
        
        if (is_wp_error($result)) {
            wp_send_json_error($result->get_error_message());
        } else if ($result) {
            wp_send_json_success('Change rolled back successfully');
        } else {
            wp_send_json_error('Failed to rollback change');
        }
    }
    
    private function get_safe_charset_collate() {
        global $wpdb;
        $charset_collate = $wpdb->get_charset_collate();
        
        if (strpos($charset_collate, 'UTF-8') !== false) {
            $charset_collate = str_replace('UTF-8', 'utf8mb4', $charset_collate);
        }
        
        if (empty($charset_collate) || strpos($charset_collate, 'UTF-8') !== false) {
            $charset_collate = 'DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci';
        }
        
        return $charset_collate;
    }
    
    private function create_audit_table() {
        global $wpdb;
        
        $charset_collate = $this->get_safe_charset_collate();
        aysa_debug_log('[AYSA DEBUG] Audit Logger using charset: ' . $charset_collate);
        
        $sql = "CREATE TABLE IF NOT EXISTS {$this->table_name} (
            id bigint(20) unsigned NOT NULL AUTO_INCREMENT,
            action_type varchar(50) NOT NULL,
            object_id bigint(20) unsigned NOT NULL,
            object_type varchar(50) NOT NULL,
            old_data longtext NULL,
            new_data longtext NULL,
            confidence_score decimal(3,2) NULL,
            is_automated tinyint(1) DEFAULT 0,
            is_rolled_back tinyint(1) DEFAULT 0,
            user_id bigint(20) unsigned NULL,
            created_at datetime DEFAULT CURRENT_TIMESTAMP,
            rolled_back_at datetime NULL,
            ip_address varchar(45) NULL,
            user_agent text NULL,
            PRIMARY KEY (id),
            KEY action_type (action_type),
            KEY object_type (object_type),
            KEY object_id (object_id),
            KEY is_automated (is_automated),
            KEY created_at (created_at)
        ) $charset_collate;";
        
        require_once(ABSPATH . 'wp-admin/includes/upgrade.php');
        dbDelta($sql);
    }
}
