<?php

/**
 * LolaCore � ActionLogger
 *
 * @package LolaCore
 * @license GPL-2.0-or-later
 */

/**
 * Action Logger
 *
 * @package LolaCore\Actions
 */

declare(strict_types=1);

namespace LolaCore\Actions;

// Exit if accessed directly.
if ( ! defined( 'ABSPATH' ) ) {
	exit;
}

/**
 * Logs all actions executed by the AI to wp_lolacore_log.
 */
class ActionLogger {

	/**
	 * Log an action execution.
	 *
	 * @param string  $actionType    e.g. 'plugin_update', 'post_create', 'db_optimize'
	 * @param string  $description   Human-readable description
	 * @param string  $status        'success'|'failed'|'cancelled'|'overridden'|'denied'|'preview'
	 * @param string  $source        'chat'|'rest' — how was this action invoked
	 * @param ?array  $details       Full data: input, output, errors, snapshots
	 * @param bool    $userOverride  True if user acted against Lola's recommendation
	 * @param ?string $lolaObjection If override, Lola's recorded objection
	 * @param ?string $sessionId     Chat session UUID (null for REST invocations)
	 * @return int Inserted row ID or 0 on failure.
	 */
	public function log( string $actionType, string $description, string $status, string $source, ?array $details = null, bool $userOverride = false, ?string $lolaObjection = null, ?string $sessionId = null ): int {
		global $wpdb;

		$table_name = $wpdb->prefix . 'lolacore_log';

		$data = array(
			'action_type'    => $actionType,
			'description'    => $description,
			'status'         => $status,
			'source'         => $source,
			'details'        => $details ? wp_json_encode( $details ) : null,
			'user_override'  => $userOverride ? 1 : 0,
			'lola_objection' => $lolaObjection,
			'session_id'     => $sessionId,
			'executed_at'    => current_time( 'mysql' ),
		);

		$format = array( '%s', '%s', '%s', '%s', '%s', '%d', '%s', '%s', '%s' );

		// phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching, PluginCheck.Security.DirectDB.UnescapedDBParameter, WordPress.DB.PreparedSQL.InterpolatedNotPrepared, WordPress.DB.PreparedSQL.NotPrepared -- Custom LolaCore table query.
		$result = $wpdb->insert( $table_name, $data, $format );

		if ( ! $result ) {
			return 0;
		}

		return (int) $wpdb->insert_id;
	}

	/**
	 * Get action history with optional filters.
	 *
	 * @param array $filters Filters for action history (e.g. action_type, status, source)
	 * @param int   $limit   Maximum number of records to return
	 * @return array History data.
	 */
	public function getHistory( array $filters = array(), int $limit = 50 ): array {
		global $wpdb;

		$table_name = $wpdb->prefix . 'lolacore_log';

		// phpcs:ignore WordPress.DB.PreparedSQL.InterpolatedNotPrepared
		$query = "SELECT * FROM $table_name WHERE 1=1";
		$args  = array();

		if ( ! empty( $filters['action_type'] ) ) {
			$query .= ' AND action_type = %s';
			$args[] = $filters['action_type'];
		}

		if ( ! empty( $filters['status'] ) ) {
			$query .= ' AND status = %s';
			$args[] = $filters['status'];
		}

		if ( ! empty( $filters['source'] ) ) {
			$query .= ' AND source = %s';
			$args[] = $filters['source'];
		}

		$query .= ' ORDER BY executed_at DESC LIMIT %d';
		$args[] = $limit;

		// phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared
		$sql = $wpdb->prepare( $query, $args );
		// phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching, PluginCheck.Security.DirectDB.UnescapedDBParameter, WordPress.DB.PreparedSQL.InterpolatedNotPrepared, WordPress.DB.PreparedSQL.NotPrepared -- Custom LolaCore table query.
		$results = $wpdb->get_results( $sql, ARRAY_A );

		// Count total matching
		// phpcs:ignore WordPress.DB.PreparedSQL.InterpolatedNotPrepared
		$count_query = "SELECT COUNT(*) FROM $table_name WHERE 1=1";
		$count_args  = array();
		if ( ! empty( $filters['action_type'] ) ) {
			$count_query .= ' AND action_type = %s';
			$count_args[] = $filters['action_type'];
		}
		if ( ! empty( $filters['status'] ) ) {
			$count_query .= ' AND status = %s';
			$count_args[] = $filters['status'];
		}
		if ( ! empty( $filters['source'] ) ) {
			$count_query .= ' AND source = %s';
			$count_args[] = $filters['source'];
		}

		$total = 0;
		if ( ! empty( $count_args ) ) {
			// phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching, PluginCheck.Security.DirectDB.UnescapedDBParameter, WordPress.DB.PreparedSQL.InterpolatedNotPrepared, WordPress.DB.PreparedSQL.NotPrepared -- Custom LolaCore table query.
			$total = (int) $wpdb->get_var( $wpdb->prepare( $count_query, $count_args ) );
		} else {
			// phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching, PluginCheck.Security.DirectDB.UnescapedDBParameter, WordPress.DB.PreparedSQL.InterpolatedNotPrepared, WordPress.DB.PreparedSQL.NotPrepared -- Custom LolaCore table query without args.
			$total = (int) $wpdb->get_var( $count_query );
		}

		return array(
			'actions' => $results,
			'total'   => $total,
		);
	}

	/**
	 * Get override history (disagreements).
	 *
	 * @param int $limit Max records.
	 * @return array Override records.
	 */
	public function getOverrides( int $limit = 20 ): array {
		global $wpdb;

		$table_name = $wpdb->prefix . 'lolacore_log';

		// phpcs:ignore WordPress.DB.PreparedSQL.InterpolatedNotPrepared
		$query = "SELECT * FROM $table_name WHERE user_override = 1 ORDER BY executed_at DESC LIMIT %d";
		// phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared
		$sql   = $wpdb->prepare( $query, $limit );

		// phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching, PluginCheck.Security.DirectDB.UnescapedDBParameter, WordPress.DB.PreparedSQL.InterpolatedNotPrepared, WordPress.DB.PreparedSQL.NotPrepared -- Custom LolaCore table query.
		return $wpdb->get_results( $sql, ARRAY_A );
	}
}