<?php
/**
 * Redirects list table. Sources AND targets are always visible — hiding
 * the destination is a top UI complaint against the category leader.
 *
 * @package RedirectZen
 */

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

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

class RDZ_Redirects_Table extends WP_List_Table {

	/**
	 * Constructor.
	 */
	public function __construct() {
		parent::__construct(
			array(
				'singular' => 'rdz_redirect',
				'plural'   => 'rdz_redirects',
				'ajax'     => false,
			)
		);
	}

	/**
	 * Columns.
	 *
	 * @return array
	 */
	public function get_columns() {
		return array(
			'cb'     => '<input type="checkbox" />',
			'source' => __( 'Source', 'redirectzen-301-redirect-manager' ),
			'target' => __( 'Target', 'redirectzen-301-redirect-manager' ),
			'type'   => __( 'Type', 'redirectzen-301-redirect-manager' ),
			'status' => __( 'Verified', 'redirectzen-301-redirect-manager' ),
			'hits'   => __( 'Hits', 'redirectzen-301-redirect-manager' ),
		);
	}

	/**
	 * Sortable columns.
	 *
	 * @return array
	 */
	protected function get_sortable_columns() {
		return array(
			'source' => array( 'source', false ),
			'hits'   => array( 'hits', true ),
			'type'   => array( 'redirect_type', false ),
		);
	}

	/**
	 * Bulk actions.
	 *
	 * @return array
	 */
	protected function get_bulk_actions() {
		return array(
			'verify'     => __( 'Verify', 'redirectzen-301-redirect-manager' ),
			'activate'   => __( 'Enable', 'redirectzen-301-redirect-manager' ),
			'deactivate' => __( 'Disable', 'redirectzen-301-redirect-manager' ),
			'delete'     => __( 'Delete', 'redirectzen-301-redirect-manager' ),
		);
	}

	/**
	 * Status filter views with counts.
	 *
	 * @return array
	 */
	protected function get_views() {
		$counts  = RDZ_Redirects::get_counts();
		$base    = admin_url( 'admin.php?page=redirectzen' );
		$current = isset( $_GET['rdz_status'] ) ? sanitize_key( wp_unslash( $_GET['rdz_status'] ) ) : ''; // phpcs:ignore WordPress.Security.NonceVerification.Recommended

		$views = array(
			''         => array( __( 'All', 'redirectzen-301-redirect-manager' ), $counts['total'] + $counts['inactive'] ),
			'ok'       => array( __( 'Working', 'redirectzen-301-redirect-manager' ), $counts['ok'] ),
			'warn'     => array( __( 'Fragile', 'redirectzen-301-redirect-manager' ), $counts['warn'] ),
			'fail'     => array( __( 'Failing', 'redirectzen-301-redirect-manager' ), $counts['fail'] ),
			'queued'   => array( __( 'Queued', 'redirectzen-301-redirect-manager' ), $counts['queued'] ),
			'inactive' => array( __( 'Disabled', 'redirectzen-301-redirect-manager' ), $counts['inactive'] ),
		);

		$links = array();
		foreach ( $views as $key => $view ) {
			if ( $key && ! $view[1] ) {
				continue;
			}
			$url           = $key ? add_query_arg( 'rdz_status', $key, $base ) : $base;
			$class         = ( $current === $key ) ? ' class="current"' : '';
			$links[ $key ] = sprintf( '<a href="%s"%s>%s <span class="count">(%s)</span></a>', esc_url( $url ), $class, esc_html( $view[0] ), number_format_i18n( $view[1] ) );
		}

		return $links;
	}

	/**
	 * Loads rows.
	 */
	public function prepare_items() {
		global $wpdb;

		$per_page = $this->get_items_per_page( 'rdz_redirects_per_page', 25 );
		$paged    = max( 1, $this->get_pagenum() );
		$table    = RDZ_Redirects::table();

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

		$status = isset( $_GET['rdz_status'] ) ? sanitize_key( wp_unslash( $_GET['rdz_status'] ) ) : ''; // phpcs:ignore WordPress.Security.NonceVerification.Recommended
		if ( 'inactive' === $status ) {
			$where[] = 'is_active = 0';
		} elseif ( in_array( $status, array( 'ok', 'warn', 'fail', 'queued', 'pending' ), true ) ) {
			$where[]  = 'is_active = 1 AND verify_status = %s';
			$params[] = $status;
		}

		$search = isset( $_REQUEST['s'] ) ? sanitize_text_field( wp_unslash( $_REQUEST['s'] ) ) : ''; // phpcs:ignore WordPress.Security.NonceVerification.Recommended
		if ( '' !== $search ) {
			$like     = '%' . $wpdb->esc_like( $search ) . '%';
			$where[]  = '(source LIKE %s OR target LIKE %s)';
			$params[] = $like;
			$params[] = $like;
		}

		$orderby = 'id';
		$order   = 'DESC';
		if ( isset( $_GET['orderby'] ) && in_array( $_GET['orderby'], array( 'source', 'hits', 'redirect_type' ), true ) ) { // phpcs:ignore WordPress.Security.NonceVerification.Recommended
			$orderby = sanitize_key( wp_unslash( $_GET['orderby'] ) ); // phpcs:ignore WordPress.Security.NonceVerification.Recommended
			$order   = ( isset( $_GET['order'] ) && 'asc' === strtolower( sanitize_key( wp_unslash( $_GET['order'] ) ) ) ) ? 'ASC' : 'DESC'; // phpcs:ignore WordPress.Security.NonceVerification.Recommended
		}

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

		// phpcs:disable WordPress.DB.PreparedSQL.InterpolatedNotPrepared, WordPress.DB.PreparedSQL.NotPrepared
		$count_sql = "SELECT COUNT(*) FROM {$table} WHERE {$where_sql}";
		$total     = (int) ( $params ? $wpdb->get_var( $wpdb->prepare( $count_sql, $params ) ) : $wpdb->get_var( $count_sql ) );

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

		$this->items = $wpdb->get_results( $wpdb->prepare( $items_sql, $args ), ARRAY_A );
		// phpcs:enable

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

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

	/**
	 * Checkbox column.
	 *
	 * @param array $item Row.
	 * @return string
	 */
	public function column_cb( $item ) {
		return sprintf( '<input type="checkbox" name="redirect_ids[]" value="%d" />', (int) $item['id'] );
	}

	/**
	 * Source column + row actions.
	 *
	 * @param array $item Row.
	 * @return string
	 */
	public function column_source( $item ) {
		$id     = (int) $item['id'];
		$source = $item['source'];
		$label  = (int) $item['is_regex'] ? '<span class="rdz-badge rdz-badge--regex">regex</span> ' : '';

		$out = '<strong><code>' . esc_html( $source ) . '</code></strong> ' . $label;
		if ( ! (int) $item['is_active'] ) {
			$out .= '<span class="rdz-badge rdz-badge--off">' . esc_html__( 'disabled', 'redirectzen-301-redirect-manager' ) . '</span>';
		}

		$actions = array(
			'edit'   => sprintf( '<a href="#" class="rdz-action" data-action="edit" data-id="%d">%s</a>', $id, esc_html__( 'Edit', 'redirectzen-301-redirect-manager' ) ),
			'verify' => sprintf( '<a href="#" class="rdz-action" data-action="verify" data-id="%d">%s</a>', $id, esc_html__( 'Verify', 'redirectzen-301-redirect-manager' ) ),
			'toggle' => sprintf(
				'<a href="#" class="rdz-action" data-action="toggle" data-id="%d" data-active="%d">%s</a>',
				$id,
				(int) $item['is_active'],
				(int) $item['is_active'] ? esc_html__( 'Disable', 'redirectzen-301-redirect-manager' ) : esc_html__( 'Enable', 'redirectzen-301-redirect-manager' )
			),
			'delete' => sprintf( '<a href="#" class="rdz-action rdz-delete" data-action="delete" data-id="%d">%s</a>', $id, esc_html__( 'Delete', 'redirectzen-301-redirect-manager' ) ),
		);

		$edit_form = sprintf(
			'<div class="rdz-inline-edit" data-id="%d" style="display:none">
				<input type="text" class="rdz-edit-source code" value="%s" aria-label="%s" %s />
				<input type="text" class="rdz-edit-target code" value="%s" aria-label="%s" />
				<select class="rdz-edit-type">%s</select>
				<button type="button" class="button button-primary rdz-save-edit">%s</button>
				<button type="button" class="button rdz-cancel-edit">%s</button>
			</div>',
			$id,
			esc_attr( $source ),
			esc_attr__( 'Source', 'redirectzen-301-redirect-manager' ),
			(int) $item['is_regex'] ? 'readonly' : '',
			esc_attr( $item['target'] ),
			esc_attr__( 'Target', 'redirectzen-301-redirect-manager' ),
			self::type_options( (int) $item['redirect_type'] ),
			esc_html__( 'Save', 'redirectzen-301-redirect-manager' ),
			esc_html__( 'Cancel', 'redirectzen-301-redirect-manager' )
		);

		return $out . $this->row_actions( $actions ) . $edit_form;
	}

	/**
	 * Options markup for the type select.
	 *
	 * @param int $selected Selected code.
	 * @return string
	 */
	private static function type_options( $selected ) {
		$out = '';
		foreach ( RDZ_Settings::$redirect_types as $code ) {
			$out .= sprintf( '<option value="%1$d"%2$s>%1$d</option>', (int) $code, selected( $selected, $code, false ) );
		}

		return $out;
	}

	/**
	 * Target column — always visible, linked.
	 *
	 * @param array $item Row.
	 * @return string
	 */
	public function column_target( $item ) {
		$target = $item['target'];
		if ( (int) $item['is_regex'] ) {
			return '<code>' . esc_html( $target ) . '</code>';
		}

		return sprintf( '<a href="%s" target="_blank" rel="noopener noreferrer">%s</a>', esc_url( $target ), esc_html( $target ) );
	}

	/**
	 * Type column.
	 *
	 * @param array $item Row.
	 * @return string
	 */
	public function column_type( $item ) {
		return esc_html( $item['redirect_type'] );
	}

	/**
	 * Verification status column.
	 *
	 * @param array $item Row.
	 * @return string
	 */
	public function column_status( $item ) {
		if ( ! (int) $item['is_active'] ) {
			return '<span class="rdz-verify rdz-verify--off">—</span>';
		}

		$status = $item['verify_status'];
		$http   = (int) $item['verify_http'];

		switch ( $status ) {
			case 'ok':
				return '<span class="rdz-verify rdz-verify--ok" title="' . esc_attr__( 'Verified: fires and lands on a working page.', 'redirectzen-301-redirect-manager' ) . '">✓ ' . esc_html__( 'Working', 'redirectzen-301-redirect-manager' ) . '</span>';
			case 'warn':
				$hint = (int) $item['verify_hops'] >= 2
					? __( 'Works, but through a redirect chain.', 'redirectzen-301-redirect-manager' )
					: __( 'Works, but lands somewhere other than the configured target.', 'redirectzen-301-redirect-manager' );
				return '<span class="rdz-verify rdz-verify--warn" title="' . esc_attr( $hint ) . '">⚠ ' . esc_html__( 'Fragile', 'redirectzen-301-redirect-manager' ) . '</span>';
			case 'fail':
				/* translators: %d: HTTP status code. */
				$hint = $http ? sprintf( __( 'Final response: HTTP %d.', 'redirectzen-301-redirect-manager' ), $http ) : __( 'The redirect did not fire or the request failed.', 'redirectzen-301-redirect-manager' );
				return '<span class="rdz-verify rdz-verify--fail" title="' . esc_attr( $hint ) . '">✕ ' . esc_html__( 'Failing', 'redirectzen-301-redirect-manager' ) . '</span>';
			case 'queued':
				return '<span class="rdz-verify rdz-verify--pending">' . esc_html__( 'Queued…', 'redirectzen-301-redirect-manager' ) . '</span>';
			default:
				return '<span class="rdz-verify rdz-verify--pending">' . esc_html__( 'Not verified', 'redirectzen-301-redirect-manager' ) . '</span>';
		}
	}

	/**
	 * Hits column.
	 *
	 * @param array $item Row.
	 * @return string
	 */
	public function column_hits( $item ) {
		$out = esc_html( number_format_i18n( (int) $item['hits'] ) );
		if ( ! empty( $item['last_hit'] ) ) {
			/* translators: %s: human-readable time difference. */
			$out .= '<br /><small>' . esc_html( sprintf( __( '%s ago', 'redirectzen-301-redirect-manager' ), human_time_diff( strtotime( $item['last_hit'] . ' UTC' ), time() ) ) ) . '</small>';
		}

		return $out;
	}

	/**
	 * Fallback column renderer.
	 *
	 * @param array  $item        Row.
	 * @param string $column_name Column.
	 * @return string
	 */
	public function column_default( $item, $column_name ) {
		return isset( $item[ $column_name ] ) ? esc_html( $item[ $column_name ] ) : '';
	}

	/**
	 * Empty-state message.
	 */
	public function no_items() {
		esc_html_e( 'No redirects yet. Add your first one above, or import from your old plugin in one click.', 'redirectzen-301-redirect-manager' );
	}
}
