<?php
/**
 * Error logging system.
 *
 * @package    WPFMJ
 * @subpackage WPFMJ/includes
 */

class WPFMJ_Error_Logger {

    /**
     * Table name.
     */
    private $table_name;

    /**
     * Constructor.
     */
    public function __construct() {
        global $wpdb;
        $this->table_name = $wpdb->prefix . 'wpfmj_error_log';
    }

    /**
     * Log an error.
     */
    public function log($automation_id, $form_entry_id, $error_type, $error_message, $retry_count = 0) {
        global $wpdb;

        return $wpdb->insert(
            $this->table_name,
            array(
                'automation_id' => intval($automation_id),
                'form_entry_id' => intval($form_entry_id),
                'error_type' => sanitize_text_field($error_type),
                'error_message' => sanitize_textarea_field($error_message),
                'retry_count' => intval($retry_count),
                'resolved' => 0
            ),
            array('%d', '%d', '%s', '%s', '%d', '%d')
        );
    }

    /**
     * Get errors for an automation.
     *
     * IMPORTANT: Results contain user-generated error messages.
     * Always escape output when displaying: esc_html(), esc_attr(), etc.
     */
    public function get_errors($automation_id, $limit = 50, $resolved = null) {
        global $wpdb;

        // Build query with proper parameter binding
        if ($resolved !== null) {
            $sql = $wpdb->prepare(
                "SELECT * FROM {$this->table_name}
                WHERE automation_id = %d AND resolved = %d
                ORDER BY created_at DESC
                LIMIT %d",
                $automation_id,
                $resolved ? 1 : 0,
                $limit
            );
        } else {
            $sql = $wpdb->prepare(
                "SELECT * FROM {$this->table_name}
                WHERE automation_id = %d
                ORDER BY created_at DESC
                LIMIT %d",
                $automation_id,
                $limit
            );
        }

        $results = $wpdb->get_results($sql, ARRAY_A);

        // Sanitize error messages for safe output
        if (is_array($results)) {
            foreach ($results as &$result) {
                $result['error_message'] = sanitize_text_field($result['error_message']);
                $result['error_type'] = sanitize_text_field($result['error_type']);
            }
        }

        return $results;
    }

    /**
     * Get error count for an automation.
     */
    public function get_error_count($automation_id, $resolved = null) {
        global $wpdb;

        // Build query with proper parameter binding
        if ($resolved !== null) {
            $sql = $wpdb->prepare(
                "SELECT COUNT(*) FROM {$this->table_name} WHERE automation_id = %d AND resolved = %d",
                $automation_id,
                $resolved ? 1 : 0
            );
        } else {
            $sql = $wpdb->prepare(
                "SELECT COUNT(*) FROM {$this->table_name} WHERE automation_id = %d",
                $automation_id
            );
        }

        return (int) $wpdb->get_var($sql);
    }

    /**
     * Get error counts for multiple automations in a single query.
     * Prevents N+1 query problems when displaying dashboard.
     *
     * @param array $automation_ids Array of automation IDs
     * @param bool|null $resolved Filter by resolved status (null = all)
     * @return array Associative array of automation_id => count
     */
    public function get_error_counts_bulk($automation_ids, $resolved = null) {
        global $wpdb;

        if (empty($automation_ids)) {
            return array();
        }

        // Sanitize all IDs
        $automation_ids = array_map('absint', $automation_ids);
        $placeholders = implode(',', array_fill(0, count($automation_ids), '%d'));

        // Build query
        if ($resolved !== null) {
            $sql = $wpdb->prepare(
                "SELECT automation_id, COUNT(*) as error_count
                FROM {$this->table_name}
                WHERE automation_id IN ($placeholders) AND resolved = %d
                GROUP BY automation_id",
                array_merge($automation_ids, array($resolved ? 1 : 0))
            );
        } else {
            $sql = $wpdb->prepare(
                "SELECT automation_id, COUNT(*) as error_count
                FROM {$this->table_name}
                WHERE automation_id IN ($placeholders)
                GROUP BY automation_id",
                $automation_ids
            );
        }

        $results = $wpdb->get_results($sql, ARRAY_A);

        // Convert to associative array
        $counts = array();
        foreach ($results as $row) {
            $counts[(int)$row['automation_id']] = (int)$row['error_count'];
        }

        return $counts;
    }

    /**
     * Mark error as resolved.
     */
    public function mark_resolved($error_id) {
        global $wpdb;

        return $wpdb->update(
            $this->table_name,
            array('resolved' => 1),
            array('id' => $error_id),
            array('%d'),
            array('%d')
        );
    }

    /**
     * Clean up old error logs.
     * 
     * @param int $days Number of days to retain resolved errors. Default 90 days.
     *                  Can be filtered using 'wpfmj_error_log_retention_days'.
     */
    public function cleanup_old_logs($days = null) {
        global $wpdb;

        // Allow filtering of retention period
        if ($days === null) {
            $days = apply_filters('wpfmj_error_log_retention_days', 90);
        }

        // Ensure positive integer
        $days = absint($days);
        if ($days < 1) {
            $days = 90; // Fallback to default
        }

        $date = gmdate('Y-m-d H:i:s', strtotime("-{$days} days"));

        $deleted = $wpdb->query(
            $wpdb->prepare(
                "DELETE FROM {$this->table_name} WHERE created_at < %s AND resolved = 1",
                $date
            )
        );

        // Log cleanup activity
        if ($deleted > 0) {
            error_log("WPFMJ: Cleaned up {$deleted} error log entries older than {$days} days");
        }

        return $deleted;
    }

    /**
     * Get recent errors across all automations.
     */
    public function get_recent_errors($limit = 20) {
        global $wpdb;

        $sql = "SELECT * FROM {$this->table_name} 
                ORDER BY created_at DESC 
                LIMIT %d";

        return $wpdb->get_results($wpdb->prepare($sql, $limit), ARRAY_A);
    }
}

// Register cleanup cron job handler
add_action('wpfmj_cleanup_error_logs', function() {
    $logger = new WPFMJ_Error_Logger();
    // Retention period can be customized via filter
    $logger->cleanup_old_logs();
});
