<?php
if (!defined('ABSPATH')) {
    exit;
}

/**
 * Automation Logger
 *
 * Centralized logging service for workflow execution with trace ID support.
 * All workflow-related logs are stored in ai_platform_workflow_logs table.
 *
 * @package    Kitsune_AI_Platform
 * @subpackage Kitsune_AI_Platform/includes/automation
 */

class Kitsune_AI_Platform_Automation_Logger {

    /**
     * Log Levels
     */
    const LEVEL_INFO    = 'info';
    const LEVEL_WARNING = 'warning';
    const LEVEL_ERROR   = 'error';
    const LEVEL_DEBUG   = 'debug';

    /**
     * Current trace ID for grouping related logs
     */
    private static $current_trace_id = null;

    /**
     * Singleton Instance
     */
    private static $instance = null;

    /**
     * Get singleton instance
     */
    public static function get_instance() {
        if (self::$instance === null) {
            self::$instance = new self();
        }
        return self::$instance;
    }

    /**
     * Constructor
     */
    private function __construct() {
        // Listen for workflow log events
        add_action('kitsune_ai_platform_log_workflow', array($this, 'log_workflow'), 10, 4);
    }

    /**
     * Generate a new trace ID (UUID v4)
     * 
     * @return string UUID
     */
    public static function start_trace() {
        self::$current_trace_id = wp_generate_uuid4();
        return self::$current_trace_id;
    }

    /**
     * Get current trace ID
     * 
     * @return string|null Current trace ID
     */
    public static function get_trace_id() {
        return self::$current_trace_id;
    }

    /**
     * Set trace ID manually (for continuing a trace)
     * 
     * @param string $trace_id The trace ID to set
     */
    public static function set_trace_id($trace_id) {
        self::$current_trace_id = $trace_id;
    }

    /**
     * Clear current trace ID
     */
    public static function end_trace() {
        self::$current_trace_id = null;
    }

    /**
     * Log a workflow event
     * 
     * @param int    $workflow_id The workflow post ID
     * @param string $level       Log level (info, warning, error, debug)
     * @param string $message     Human-readable log message
     * @param array  $context     Additional context data
     * @return int|false Log entry ID or false on failure
     */
    public function log_workflow($workflow_id, $level, $message, $context = array()) {
        return $this->log('workflow', $workflow_id, $level, $message, $context);
    }

    /**
     * Core logging method
     * 
     * @param string $log_type    Log category (currently only 'workflow')
     * @param int    $workflow_id The workflow post ID (nullable)
     * @param string $level       Log level
     * @param string $message     Human-readable log message
     * @param array  $context     Additional context data
     * @return int|false Log entry ID or false on failure
     */
    public function log($log_type, $workflow_id, $level, $message, $context = array()) {
        global $wpdb;
        $table = $wpdb->prefix . 'kitsune_ai_platform_workflow_logs';

        // Ensure we have a trace ID
        $trace_id = self::$current_trace_id;
        if (empty($trace_id)) {
            $trace_id = self::start_trace();
        }

        // Validate level
        $valid_levels = array(self::LEVEL_INFO, self::LEVEL_WARNING, self::LEVEL_ERROR, self::LEVEL_DEBUG);
        if (!in_array($level, $valid_levels)) {
            $level = self::LEVEL_INFO;
        }

        // Prepare context - ensure it's JSON serializable
        $safe_context = $this->sanitize_context($context);

        $result = $wpdb->insert($table, array(
            'trace_id'    => $trace_id,
            'workflow_id' => $workflow_id ? intval($workflow_id) : 0,
            'log_type'    => sanitize_text_field($log_type),
            'level'       => $level,
            'status'      => $level,  // mirrors level; required by schema
            'message'     => sanitize_text_field($message),
            'context'     => json_encode($safe_context),
            'created_at'  => current_time('mysql')
        ), array('%s', '%d', '%s', '%s', '%s', '%s', '%s', '%s'));

        if ($wpdb->last_error) {
            if (defined('WP_DEBUG') && WP_DEBUG) {
                error_log('AI Platform Logger Error: ' . $wpdb->last_error);
            }
            return false;
        }

        return $wpdb->insert_id;
    }

    /**
     * Retrieve logs with filtering and pagination
     * 
     * @param array $filters Filter options
     * @param int   $page    Page number (1-indexed)
     * @param int   $per_page Items per page
     * @return array Array with 'logs', 'total', 'pages'
     */
    public function get_logs($filters = array(), $page = 1, $per_page = 20) {
        global $wpdb;
        $table = $wpdb->prefix . 'kitsune_ai_platform_workflow_logs';

        $where = array('1=1');
        $params = array();

        // Filter by workflow_id
        if (!empty($filters['workflow_id'])) {
            $where[] = 'workflow_id = %d';
            $params[] = intval($filters['workflow_id']);
        }

        // Filter by level
        if (!empty($filters['level'])) {
            $where[] = 'level = %s';
            $params[] = sanitize_text_field($filters['level']);
        }

        // Filter by trace_id
        if (!empty($filters['trace_id'])) {
            $where[] = 'trace_id = %s';
            $params[] = sanitize_text_field($filters['trace_id']);
        }

        // Filter by date range
        if (!empty($filters['date_from'])) {
            $where[] = 'created_at >= %s';
            $params[] = sanitize_text_field($filters['date_from']);
        }
        if (!empty($filters['date_to'])) {
            $where[] = 'created_at <= %s';
            $params[] = sanitize_text_field($filters['date_to']);
        }

        // Search in message or context
        if (!empty($filters['search'])) {
            $search_term = '%' . $wpdb->esc_like($filters['search']) . '%';
            $where[] = '(message LIKE %s OR context LIKE %s)';
            $params[] = $search_term;
            $params[] = $search_term;
        }

        $where_clause = implode(' AND ', $where);

        // Count total
        $count_sql = "SELECT COUNT(*) FROM {$table} WHERE {$where_clause}";
        if (!empty($params)) {
            $count_sql = $wpdb->prepare($count_sql, $params);
        }
        $total = $wpdb->get_var($count_sql);

        // Calculate pagination
        $offset = ($page - 1) * $per_page;
        $pages = ceil($total / $per_page);

        // Get logs
        $sql = "SELECT * FROM {$table} WHERE {$where_clause} ORDER BY created_at DESC LIMIT %d OFFSET %d";
        $params[] = $per_page;
        $params[] = $offset;
        
        $logs = $wpdb->get_results($wpdb->prepare($sql, $params));

        // Decode context JSON
        foreach ($logs as &$log) {
            $log->context = json_decode($log->context, true);
        }

        return array(
            'logs'  => $logs,
            'total' => (int)$total,
            'pages' => (int)$pages,
            'page'  => (int)$page
        );
    }

    /**
     * Get logs by trace ID (for viewing related logs in order)
     * 
     * @param string $trace_id The trace ID to fetch
     * @return array Array of log entries ordered by timestamp
     */
    public function get_logs_by_trace($trace_id) {
        global $wpdb;
        $table = $wpdb->prefix . 'kitsune_ai_platform_workflow_logs';

        $sql = $wpdb->prepare(
            "SELECT * FROM {$table} WHERE trace_id = %s ORDER BY created_at ASC",
            $trace_id
        );

        $logs = $wpdb->get_results($sql);

        // Decode context JSON
        foreach ($logs as &$log) {
            $log->context = json_decode($log->context, true);
        }

        return $logs;
    }

    /**
     * Delete old logs (for cleanup)
     * 
     * @param int $days_old Delete logs older than this many days
     * @return int Number of deleted rows
     */
    public function cleanup_old_logs($days_old = 30) {
        global $wpdb;
        $table = $wpdb->prefix . 'kitsune_ai_platform_workflow_logs';

        $result = $wpdb->query($wpdb->prepare(
            "DELETE FROM {$table} WHERE created_at < DATE_SUB(NOW(), INTERVAL %d DAY)",
            $days_old
        ));

        return $result;
    }

    /**
     * Sanitize context array for JSON storage
     * Removes objects and very large values
     * 
     * @param array $context Raw context data
     * @return array Sanitized context
     */
    private function sanitize_context($context) {
        if (!is_array($context)) {
            return array();
        }

        $safe = array();
        foreach ($context as $key => $value) {
            // Skip objects (WP_Post, WP_Comment, etc.)
            if (is_object($value)) {
                continue;
            }
            // Skip very large strings (> 1000 chars)
            if (is_string($value) && strlen($value) > 1000) {
                $safe[$key] = substr($value, 0, 1000) . '... [truncated]';
                continue;
            }
            // Recursively sanitize arrays
            if (is_array($value)) {
                $safe[$key] = $this->sanitize_context($value);
                continue;
            }
            $safe[$key] = $value;
        }

        return $safe;
    }
}
