<?php
/**
 * WP_List_Table implementation for Mail Doctor email logs.
 *
 * @package MailDoctor
 */

namespace MailDoctor;

use MailDoctor\Logger;
use MailDoctor\Retry;
use WP_List_Table;

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

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

if ( ! class_exists( '\MailDoctor\Logs_Table' ) ) {
	/**
	 * Logs list table scaffold.
	 */
	class Logs_Table extends WP_List_Table {

		/**
		 * Constructor.
		 */
		public function __construct() {
			parent::__construct(
				array(
					'singular' => 'maildoctor-log',
					'plural'   => 'maildoctor-logs',
					'ajax'     => false,
				)
			);
		}

		/**
		 * Prepare items for display.
		 *
		 * @return void
		 */
		public function prepare_items(): void {
			$this->process_bulk_action();

			$columns  = $this->get_columns();
			$hidden   = array();
			$sortable = array();

			$this->_column_headers = array( $columns, $hidden, $sortable );

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

			$args = Admin::get_log_query_args();

			$args['paged']    = $current_page;
			$args['per_page'] = $per_page;

			$results = Logger::query( $args );
			$raw     = isset( $results['items'] ) ? (array) $results['items'] : array();

			$items = array();

			foreach ( $raw as $row ) {
				$items[] = Admin::prepare_log_item( $row );
			}

			$this->items = $items;

			$total_items = isset( $results['total'] ) ? (int) $results['total'] : count( $items );

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

		/**
		 * Columns definition.
		 *
		 * @return array<string,string>
		 */
		public function get_columns(): array {
			return array(
				'cb'       => '<input type="checkbox" />',
				'time'     => esc_html__( 'Time', 'mail-doctor' ),
				'event'    => esc_html__( 'Event', 'mail-doctor' ),
				'to'       => esc_html__( 'Recipient', 'mail-doctor' ),
				'subject'  => esc_html__( 'Subject', 'mail-doctor' ),
				'status'   => esc_html__( 'Status', 'mail-doctor' ),
				'latency'  => esc_html__( 'Latency (ms)', 'mail-doctor' ),
				'attempts' => esc_html__( 'Attempts', 'mail-doctor' ),
				'actions'  => esc_html__( 'Actions', 'mail-doctor' ),
			);
		}

		/**
		 * Bulk actions.
		 *
		 * @return array<string,string>
		 */
		protected function get_bulk_actions(): array {
			return array(
				'retry-selected'  => esc_html__( 'Retry', 'mail-doctor' ),
				'delete-selected' => esc_html__( 'Delete', 'mail-doctor' ),
			);
		}

		/**
		 * Checkbox column.
		 *
		 * @param array<string,mixed> $item Item.
		 * @return string
		 */
		protected function column_cb( $item ): string {
			return sprintf(
				'<input type="checkbox" name="log_ids[]" value="%1$d" />',
				absint( $item['id'] )
			);
		}

		/**
		 * Default column handler.
		 *
		 * @param array<string,mixed> $item Item.
		 * @param string              $column_name Column key.
		 * @return string
		 */
		protected function column_default( $item, $column_name ): string {
			switch ( $column_name ) {
				case 'latency':
					if ( ! empty( $item['latency'] ) ) {
						return esc_html( number_format_i18n( (int) $item['latency'] ) );
					}
					return '&mdash;';
				case 'attempts':
					return esc_html( number_format_i18n( (int) $item['attempts'] ) );
				case 'event':
				case 'subject':
					return esc_html( (string) $item[ $column_name ] );
				case 'time':
					return esc_html( (string) $item['time_display'] );
				case 'to':
					return esc_html( (string) $item['recipient'] );
			}

			return '';
		}

		/**
		 * Status column with pill.
		 *
		 * @param array<string,mixed> $item Item.
		 * @return string
		 */
		protected function column_status( $item ): string {
			$status  = sanitize_key( $item['status'] );
			$classes = array( 'mail-doctor-badge' );

			switch ( $status ) {
				case 'sent':
					$classes[] = 'is-ok';
					break;
				case 'failed':
					$classes[] = 'is-fail';
					break;
				default:
					$classes[] = 'is-warn';
					break;
			}

			$label = esc_html( $item['status_label'] ?? ucfirst( $status ) );

			return sprintf( '<span class="%1$s"><span class="screen-reader-text">%2$s </span>%3$s</span>', esc_attr( implode( ' ', $classes ) ), esc_html__( 'Status:', 'mail-doctor' ), $label );
		}

		/**
		 * Actions column.
		 *
		 * @param array<string,mixed> $item Item.
		 * @return string
		 */
		protected function column_actions( $item ): string {
			$modal   = isset( $item['modal'] ) && is_array( $item['modal'] ) ? $item['modal'] : array();
			$encoded = wp_json_encode( $modal );

			// Build EML download URL separately (not in JSON to avoid esc_attr breaking & chars).
			$eml_url = '';
			$id      = absint( $item['id'] ?? 0 );
			if ( $id && \MailDoctor\Features::is_enabled( 'eml_download' ) ) {
				$eml_url = wp_nonce_url(
					add_query_arg(
						array(
							'action' => 'mail_doctor_export_eml',
							'log_id' => $id,
						),
						admin_url( 'admin-post.php' )
					),
					'mail_doctor_export_eml_' . $id
				);
			}

			$view = sprintf(
				'<a href="#" class="mail-doctor-log-action mail-doctor-view-log" data-log="%1$s" data-eml-url="%2$s">%3$s</a>',
				esc_attr( $encoded ),
				esc_url( $eml_url ),
				esc_html__( 'View', 'mail-doctor' )
			);

			$retry = '';

			if ( 'failed' === $item['status'] ) {
				$retry = sprintf(
					'<a href="#" class="mail-doctor-log-action mail-doctor-retry-log" data-log-id="%1$d">%2$s</a>',
					absint( $item['id'] ),
					esc_html__( 'Retry', 'mail-doctor' )
				);
			}

			$resend = sprintf(
				'<a href="#" class="mail-doctor-log-action mail-doctor-resend-log" data-log-id="%1$d">%2$s</a>',
				absint( $item['id'] ),
				esc_html__( 'Resend', 'mail-doctor' )
			);

			$resend_alt = sprintf(
				'<a href="#" class="mail-doctor-log-action mail-doctor-resend-log" data-log-id="%1$d" data-mode="alternate">%2$s</a>',
				absint( $item['id'] ),
				esc_html__( 'Resend to…', 'mail-doctor' )
			);

			$actions = array_filter( array( $view, $retry, $resend, $resend_alt ) );

			return implode( ' | ', $actions );
		}

		/**
		 * Text when no items.
		 *
		 * @return void
		 */
		public function no_items() {
			esc_html_e( 'No email logs recorded yet.', 'mail-doctor' );
		}

		/**
		 * Handle bulk actions submitted from the list table.
		 *
		 * @return void
		 */
		protected function process_bulk_action() {
			$action = $this->current_action();

			if ( ! in_array( $action, array( 'retry-selected', 'delete-selected' ), true ) ) {
				return;
			}

			check_admin_referer( 'bulk-' . $this->_args['plural'] );

			// phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotSanitized -- Sanitized via absint in the loop below.
		$raw_ids = isset( $_POST['log_ids'] ) ? (array) wp_unslash( $_POST['log_ids'] ) : array();
			$log_ids = array();

			foreach ( $raw_ids as $id ) {
				$id = absint( $id );
				if ( $id > 0 ) {
					$log_ids[] = $id;
				}
			}

			if ( empty( $log_ids ) ) {
				add_settings_error( 'maildoctor', 'mail_doctor_logs_empty', esc_html__( 'Select at least one log entry before running a bulk action.', 'mail-doctor' ), 'error' );
				return;
			}

			if ( 'retry-selected' === $action ) {
				$this->handle_bulk_retry( $log_ids );
			} elseif ( 'delete-selected' === $action ) {
				$this->handle_bulk_delete( $log_ids );
			}
		}

		/**
		 * Bulk retry selected log IDs.
		 *
		 * @param array<int> $log_ids Log identifiers.
		 * @return void
		 */
		protected function handle_bulk_retry( array $log_ids ): void {
			$success = 0;
			$errors  = array();

			foreach ( $log_ids as $log_id ) {
				$result = Retry::manual_retry( $log_id );

				if ( is_wp_error( $result ) ) {
					$errors[] = $result->get_error_message();
					continue;
				}

				++$success;
			}

			if ( $success > 0 ) {
				$message = sprintf(
					/* translators: %d: number of log entries queued for retry. */
					_n( 'Queued retry for %d email.', 'Queued retry for %d emails.', $success, 'mail-doctor' ),
					$success
				);
				add_settings_error( 'maildoctor', 'mail_doctor_logs_retry', esc_html( $message ), 'updated' );
			}

			if ( ! empty( $errors ) ) {
				$unique  = array_unique( $errors );
				$message = implode( ' ', array_map( 'esc_html', $unique ) );
				add_settings_error( 'maildoctor', 'mail_doctor_logs_retry_error', $message, 'error' );
			}
		}

		/**
		 * Bulk delete selected log IDs.
		 *
		 * @param array<int> $log_ids Log identifiers.
		 * @return void
		 */
		protected function handle_bulk_delete( array $log_ids ): void {
			$deleted = Logger::delete_logs( $log_ids );

			if ( $deleted > 0 ) {
				$message = sprintf(
					/* translators: %d: number of log entries deleted. */
					_n( 'Deleted %d log entry.', 'Deleted %d log entries.', $deleted, 'mail-doctor' ),
					$deleted
				);
				add_settings_error( 'maildoctor', 'mail_doctor_logs_delete', esc_html( $message ), 'updated' );
				return;
			}

			add_settings_error( 'maildoctor', 'mail_doctor_logs_delete_empty', esc_html__( 'No logs were deleted. They may have already been removed.', 'mail-doctor' ), 'error' );
		}
	}
}
