<?php
/**
 * Activity_List_Table — WP_List_Table view over wp_ppok_ai_events.
 *
 * @package Ppok\AIToolkit
 * @license GPL-2.0-or-later
 */

namespace Ppok\AIToolkit\Admin;

use Ppok\AIToolkit\Event_Logger;

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

if ( ! class_exists( '\WP_List_Table' ) ) {
	require_once ABSPATH . 'wp-admin/includes/class-wp-list-table.php';
}

final class Activity_List_Table extends \WP_List_Table {

	private string $base_url;

	public function __construct( string $base_url = '' ) {
		parent::__construct(
			array(
				'singular' => 'ppok_ai_event',
				'plural'   => 'ppok_ai_events',
				'ajax'     => false,
				'screen'   => 'settings_page_ppok-ai-toolkit',
			)
		);
		$this->base_url = '' !== $base_url
			? $base_url
			: admin_url( 'options-general.php?page=ppok-ai-toolkit&tab=activity' );
	}

	public function get_columns(): array {
		return array(
			'created_at'  => __( 'When', 'ppok-ai-toolkit' ),
			'ability'     => __( 'Call', 'ppok-ai-toolkit' ),
			'result'      => __( 'Result', 'ppok-ai-toolkit' ),
			'actor'       => __( 'Actor', 'ppok-ai-toolkit' ),
			'target'      => __( 'Target post', 'ppok-ai-toolkit' ),
			'reason'      => __( 'Reason', 'ppok-ai-toolkit' ),
			'mcp_client'  => __( 'Client', 'ppok-ai-toolkit' ),
			'correlation' => __( 'Correlation', 'ppok-ai-toolkit' ),
		);
	}

	protected function get_sortable_columns(): array {
		return array(
			'created_at' => array( 'created_at', true ),
			'result'     => array( 'result', false ),
			'ability'    => array( 'ability_slug', false ),
		);
	}

	public function prepare_items(): void {
		global $wpdb;

		$this->_column_headers = array( $this->get_columns(), array(), $this->get_sortable_columns() );

		$per_page     = 25;
		$current_page = max( 1, (int) $this->get_pagenum() );

		[ $where_sql, $params ] = $this->build_where();

		$table   = Event_Logger::table_name();
		$orderby = $this->sanitized_orderby();
		$order   = $this->sanitized_order();
		$offset  = ( $current_page - 1 ) * $per_page;

		$query = "SELECT * FROM {$table} {$where_sql} ORDER BY {$orderby} {$order} LIMIT %d OFFSET %d";
		$args  = array_merge( $params, array( $per_page, $offset ) );

		// phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared -- table name + orderby/order are sanitized above.
		$prepared    = $wpdb->prepare( $query, $args );
		$this->items = $wpdb->get_results( $prepared, ARRAY_A ) ?: array();

		$count_query = "SELECT COUNT(*) FROM {$table} {$where_sql}";
		// phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared -- same prepared inputs as above.
		$total = (int) $wpdb->get_var( $params ? $wpdb->prepare( $count_query, $params ) : $count_query );

		$this->set_pagination_args(
			array(
				'total_items' => $total,
				'per_page'    => $per_page,
				'total_pages' => (int) ceil( $total / $per_page ),
			)
		);
	}

	/**
	 * Build the WHERE clause + placeholder array from the current $_GET filters.
	 *
	 * @return array{0:string,1:array<int,mixed>}
	 */
	private function build_where(): array {
		$conds  = array();
		$params = array();

		$equals = array(
			'ability_slug'   => array( 'in', 191 ),
			'result'         => array( 'in', 32 ),
			'error_code'     => array( 'in', 64 ),
			'correlation_id' => array( 'in', 64 ),
			'mcp_client'     => array( 'in', 191 ),
		);
		foreach ( $equals as $col => $cfg ) {
			$value = isset( $_GET[ $col ] ) ? trim( (string) wp_unslash( $_GET[ $col ] ) ) : '';
			if ( '' === $value ) {
				continue;
			}
			$conds[]  = "{$col} = %s";
			$params[] = substr( sanitize_text_field( $value ), 0, $cfg[1] );
		}

		$actor = isset( $_GET['actor_user_id'] ) ? (int) $_GET['actor_user_id'] : 0;
		if ( $actor > 0 ) {
			$conds[]  = 'actor_user_id = %d';
			$params[] = $actor;
		}

		$target = isset( $_GET['target_post_id'] ) ? (int) $_GET['target_post_id'] : 0;
		if ( $target > 0 ) {
			$conds[]  = 'target_post_id = %d';
			$params[] = $target;
		}

		$from = isset( $_GET['from'] ) ? sanitize_text_field( (string) wp_unslash( $_GET['from'] ) ) : '';
		if ( '' !== $from && preg_match( '/^\d{4}-\d{2}-\d{2}$/', $from ) ) {
			$conds[]  = 'created_at >= %s';
			$params[] = $from . ' 00:00:00';
		}

		$to = isset( $_GET['to'] ) ? sanitize_text_field( (string) wp_unslash( $_GET['to'] ) ) : '';
		if ( '' !== $to && preg_match( '/^\d{4}-\d{2}-\d{2}$/', $to ) ) {
			$conds[]  = 'created_at <= %s';
			$params[] = $to . ' 23:59:59';
		}

		$search = isset( $_GET['s'] ) ? trim( (string) wp_unslash( $_GET['s'] ) ) : '';
		if ( '' !== $search ) {
			global $wpdb;
			$conds[]  = 'reason LIKE %s';
			$params[] = '%' . $wpdb->esc_like( $search ) . '%';
		}

		$where = $conds ? 'WHERE ' . implode( ' AND ', $conds ) : '';
		return array( $where, $params );
	}

	private function sanitized_orderby(): string {
		$allowed = array( 'created_at', 'ability_slug', 'result', 'id' );
		$req     = isset( $_GET['orderby'] ) ? sanitize_key( (string) wp_unslash( $_GET['orderby'] ) ) : 'created_at';
		return in_array( $req, $allowed, true ) ? $req : 'created_at';
	}

	private function sanitized_order(): string {
		$req = isset( $_GET['order'] ) ? strtoupper( sanitize_key( (string) wp_unslash( $_GET['order'] ) ) ) : 'DESC';
		return 'ASC' === $req ? 'ASC' : 'DESC';
	}

	public function column_default( $item, $column_name ) {
		return isset( $item[ $column_name ] ) ? esc_html( (string) $item[ $column_name ] ) : '';
	}

	public function column_created_at( array $item ): string {
		$ts     = strtotime( (string) $item['created_at'] . ' UTC' );
		$detail = add_query_arg(
			array(
				'action' => 'view',
				'id'     => (int) $item['id'],
			),
			$this->base_url
		);
		return sprintf(
			'<a href="%s">%s</a>',
			esc_url( $detail ),
			esc_html( $ts ? gmdate( 'Y-m-d H:i:s', $ts ) . ' UTC' : (string) $item['created_at'] )
		);
	}

	public function column_ability( array $item ): string {
		$slug    = (string) $item['ability_slug'];
		$payload = $this->decode_payload( $item );
		$label   = esc_html( $slug );

		if ( 'ppok/rest-call' === $slug && isset( $payload['input_args']['method'], $payload['input_args']['path'] ) ) {
			$method = strtoupper( (string) $payload['input_args']['method'] );
			$path   = (string) $payload['input_args']['path'];
			$label .= sprintf(
				' <br /><code style="font-size:11px;color:#646970">%s %s</code>',
				esc_html( $method ),
				esc_html( $path )
			);
		}

		return $label;
	}

	public function column_result( array $item ): string {
		$result = (string) $item['result'];
		$err    = (string) ( $item['error_code'] ?? '' );
		$color  = 'ok' === $result ? '#00a32a' : '#d63638';

		$out = sprintf(
			'<strong style="color:%s">%s</strong>',
			esc_attr( $color ),
			esc_html( $result )
		);

		if ( '' !== $err ) {
			$out .= '<br /><code style="font-size:11px">' . esc_html( $err ) . '</code>';
		}
		return $out;
	}

	public function column_actor( array $item ): string {
		$uid = (int) ( $item['actor_user_id'] ?? 0 );
		if ( $uid <= 0 ) {
			return '&mdash;';
		}
		$user = get_userdata( $uid );
		if ( ! $user ) {
			return esc_html( '#' . $uid );
		}
		return sprintf( '%s <br /><span style="color:#646970">#%d</span>', esc_html( $user->user_login ), $uid );
	}

	public function column_target( array $item ): string {
		$pid = (int) ( $item['target_post_id'] ?? 0 );
		if ( $pid <= 0 ) {
			return '&mdash;';
		}
		$title = get_the_title( $pid );
		$edit  = get_edit_post_link( $pid );
		if ( $edit && $title ) {
			return sprintf( '<a href="%s">%s</a> <br /><span style="color:#646970">#%d</span>', esc_url( $edit ), esc_html( $title ), $pid );
		}
		return esc_html( (string) $pid );
	}

	public function column_reason( array $item ): string {
		$reason = (string) ( $item['reason'] ?? '' );
		if ( '' === $reason ) {
			return '&mdash;';
		}
		if ( strlen( $reason ) > 120 ) {
			return esc_html( substr( $reason, 0, 117 ) ) . '&hellip;';
		}
		return esc_html( $reason );
	}

	public function column_mcp_client( array $item ): string {
		$client = (string) ( $item['mcp_client'] ?? '' );
		if ( '' === $client ) {
			return '&mdash;';
		}
		return esc_html( $client );
	}

	public function column_correlation( array $item ): string {
		$cid = (string) ( $item['correlation_id'] ?? '' );
		if ( '' === $cid ) {
			return '&mdash;';
		}
		return '<code style="font-size:11px">' . esc_html( substr( $cid, 0, 12 ) ) . '&hellip;</code>';
	}

	public function no_items(): void {
		esc_html_e( 'No AI events recorded yet.', 'ppok-ai-toolkit' );
	}

	/**
	 * @return array<string, mixed>
	 */
	private function decode_payload( array $item ): array {
		if ( empty( $item['payload'] ) ) {
			return array();
		}
		$decoded = json_decode( (string) $item['payload'], true );
		return is_array( $decoded ) ? $decoded : array();
	}
}
