<?php
/**
 * Admin Quote Inbox — WP Admin page listing all submitted quotes.
 *
 * Registers a submenu under the Tilvora CPT menu. Provides:
 *  - Filterable / searchable / paginated list table (WP_List_Table)
 *  - Single-quote detail view
 *  - Status management: New / Replied / Completed (inline AJAX + GET fallback)
 *  - Bulk actions: delete, mark replied, mark completed
 */

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

// WP_List_Table is only loaded by WordPress during the admin bootstrap, which happens
// after plugins are loaded. Require it here so the class declaration below can extend it.
if ( is_admin() && ! class_exists( 'WP_List_Table' ) ) {
	require_once ABSPATH . 'wp-admin/includes/class-wp-list-table.php';
}

/* ── Menu registration ────────────────────────────────────────────────── */

add_action( 'admin_menu', 'tilvora_register_quote_inbox_menu' );

function tilvora_register_quote_inbox_menu() {
	$new_count   = tilvora_count_quotes( 'new' );
	$menu_label  = __( 'Quote Inbox', 'tilvora-3d-flooring-visualizer' );
	if ( $new_count > 0 ) {
		$menu_label .= ' <span class="awaiting-mod">' . absint( $new_count ) . '</span>';
	}

	$hook = add_submenu_page(
		'edit.php?post_type=' . TILVORA_CPT,
		__( 'Quote Inbox', 'tilvora-3d-flooring-visualizer' ),
		$menu_label,
		'manage_options',
		'tilvora-quotes',
		'tilvora_render_quotes_page'
	);

	add_action( "admin_print_styles-{$hook}", 'tilvora_enqueue_quote_inbox_assets' );
	// Must run on "load-{$hook}" (before any admin page HTML is output), not inside
	// the page render callback — wp_safe_redirect() inside the render callback fails
	// silently ("headers already sent", since admin-header.php has already printed
	// output by then), which was why delete/bulk-delete appeared to do nothing.
	add_action( "load-{$hook}", 'tilvora_handle_quote_page_actions' );
}

function tilvora_handle_quote_page_actions() {
	if ( ! current_user_can( 'manage_options' ) ) {
		return;
	}

	$action = sanitize_text_field( wp_unslash( $_GET['action'] ?? '' ) );

	// GET action: delete single quote.
	if ( 'delete' === $action && ! empty( $_GET['id'] ) ) {
		$id = absint( $_GET['id'] );
		check_admin_referer( 'tilvora_delete_quote_' . $id );
		tilvora_delete_quotes( $id );
		wp_safe_redirect( add_query_arg(
			array( 'page' => 'tilvora-quotes', 'deleted' => 1 ),
			admin_url( 'edit.php?post_type=' . TILVORA_CPT )
		) );
		exit;
	}

	// GET action: update status (fallback without JS).
	if ( 'update_status' === $action && ! empty( $_GET['id'] ) && ! empty( $_GET['status'] ) ) {
		$id     = absint( $_GET['id'] );
		$status = sanitize_key( $_GET['status'] );
		check_admin_referer( 'tilvora_status_' . $id );
		tilvora_update_quote_status( $id, $status );
		wp_safe_redirect( add_query_arg(
			array( 'page' => 'tilvora-quotes', 'action' => 'view', 'id' => $id ),
			admin_url( 'edit.php?post_type=' . TILVORA_CPT )
		) );
		exit;
	}

	// Bulk actions (delete / mark replied / mark completed) from the list table's
	// own form — process_bulk_action() no-ops if none was submitted, and otherwise
	// redirects + exits itself once done.
	if ( class_exists( 'Tilvora_Quotes_List_Table' ) ) {
		$table = new Tilvora_Quotes_List_Table();
		$table->process_bulk_action();
	}
}

/* ── Assets (CSS + JS) ────────────────────────────────────────────────── */

function tilvora_enqueue_quote_inbox_assets() {
	// Phantom style handle — inline CSS attached below.
	wp_register_style( 'tilvora-quote-inbox', false, array( 'common' ), TILVORA_VERSION );
	wp_enqueue_style( 'tilvora-quote-inbox' );
	wp_add_inline_style( 'tilvora-quote-inbox', tilvora_quote_inbox_css() );

	// Phantom script handle — inline JS attached below.
	wp_register_script( 'tilvora-quote-inbox-js', false, array(), TILVORA_VERSION, true );
	wp_enqueue_script( 'tilvora-quote-inbox-js' );

	// Pass the nonce to JS for AJAX status updates.
	wp_add_inline_script(
		'tilvora-quote-inbox-js',
		'var ffqNonce = ' . wp_json_encode( wp_create_nonce( 'tilvora_update_quote_status' ) ) . ';',
		'before'
	);
	wp_add_inline_script( 'tilvora-quote-inbox-js', tilvora_quote_inbox_js() );
}

function tilvora_quote_inbox_css() {
	return '
.fv-status-badge {
	display: inline-block;
	padding: 2px 10px;
	border-radius: 99px;
	font-size: 12px;
	font-weight: 600;
	letter-spacing: .3px;
	line-height: 1.8;
}
.fv-status-new       { background: #dbeafe; color: #1d4ed8; }
.fv-status-replied   { background: #fef9c3; color: #854d0e; }
.fv-status-completed { background: #dcfce7; color: #166534; }

.fv-status-actions { margin-top: 6px; display: flex; gap: 6px; flex-wrap: wrap; }
.fv-set-status {
	font-size: 12px;
	padding: 2px 8px;
	border-radius: 4px;
	border: 1px solid currentColor;
	text-decoration: none;
	line-height: 1.6;
	cursor: pointer;
	background: transparent;
	transition: opacity .15s;
}
.fv-set-status:hover { opacity: .75; }
.fv-set-status[data-status="new"]       { color: #1d4ed8; }
.fv-set-status[data-status="replied"]   { color: #854d0e; }
.fv-set-status[data-status="completed"] { color: #166534; }
.fv-set-status.is-current { opacity: .35; pointer-events: none; }

/* ── Detail view ── */
.fv-detail-wrap { max-width: 800px; }
.fv-detail-card {
	background: #fff;
	border: 1px solid #c3c4c7;
	border-radius: 4px;
	padding: 20px 24px;
	margin-bottom: 20px;
}
.fv-detail-card h3 {
	margin-top: 0;
	font-size: 14px;
	text-transform: uppercase;
	letter-spacing: .5px;
	color: #646970;
	border-bottom: 1px solid #f0f0f0;
	padding-bottom: 8px;
	margin-bottom: 14px;
}
.fv-detail-row {
	display: flex;
	gap: 16px;
	padding: 5px 0;
	border-bottom: 1px solid #f6f7f7;
	font-size: 14px;
}
.fv-detail-row:last-child { border-bottom: none; }
.fv-detail-label {
	flex: 0 0 140px;
	color: #646970;
	font-weight: 600;
}
.fv-detail-value { flex: 1; }
.fv-detail-notes { white-space: pre-wrap; word-break: break-word; }

.fv-quote-status-bar {
	display: flex;
	align-items: center;
	gap: 16px;
	margin-bottom: 20px;
	padding: 14px 20px;
	background: #fff;
	border: 1px solid #c3c4c7;
	border-radius: 4px;
}
.fv-quote-status-bar strong { margin-right: 6px; }

/* ── Design image — list thumbnail ── */
.fv-design-thumb {
	display: block;
	width: 160px;
	height: 90px;
	object-fit: cover;
	border-radius: 4px;
	border: 1px solid #dcdcde;
	margin-bottom: 6px;
	background: #f0f0f1;
}

/* ── Design image — detail view ── */
.fv-design-image-wrap {
	margin-bottom: 16px;
	border-radius: 6px;
	overflow: hidden;
	border: 1px solid #dcdcde;
	background: #1a1a1a;
	line-height: 0;
}
.fv-design-image-wrap img {
	width: 100%;
	max-height: 420px;
	object-fit: contain;
	display: block;
}
.fv-design-image-dl {
	display: inline-block;
	margin-top: 8px;
	font-size: 12px;
	color: #2271b1;
}
';
}

function tilvora_quote_inbox_js() {
	return '
(function () {
	document.addEventListener("DOMContentLoaded", function () {

		/* Inline status change via AJAX with GET-link fallback */
		document.querySelectorAll(".fv-set-status").forEach(function (btn) {
			btn.addEventListener("click", function (e) {
				e.preventDefault();

				var id     = btn.dataset.id;
				var status = btn.dataset.status;
				var badge  = document.getElementById("fv-badge-" + id);

				var labels = { "new": "New", "replied": "Replied", "completed": "Completed" };
				var classes = {
					"new":       "fv-status-badge fv-status-new",
					"replied":   "fv-status-badge fv-status-replied",
					"completed": "fv-status-badge fv-status-completed"
				};

				var fd = new FormData();
				fd.append("action", "tilvora_update_quote_status");
				fd.append("nonce",  ffqNonce);
				fd.append("id",     id);
				fd.append("status", status);

				fetch(ajaxurl, { method: "POST", body: fd })
					.then(function (r) { return r.json(); })
					.then(function (res) {
						if (!res.success) { window.location.reload(); return; }

						if (badge) {
							badge.className   = classes[status] || "fv-status-badge";
							badge.textContent = labels[status] || status;
						}

						/* Update current-state styling on sibling buttons */
						var container = btn.closest(".fv-status-actions");
						if (container) {
							container.querySelectorAll(".fv-set-status").forEach(function (b) {
								b.classList.toggle("is-current", b.dataset.status === status);
							});
						}
					})
					.catch(function () { window.location.reload(); });
			});
		});
	});
})();
';
}

/* ── AJAX handler: update quote status (admin-only) ─────────────────── */

add_action( 'wp_ajax_tilvora_update_quote_status', 'tilvora_ajax_update_quote_status' );

function tilvora_ajax_update_quote_status() {
	check_ajax_referer( 'tilvora_update_quote_status', 'nonce' );

	if ( ! current_user_can( 'manage_options' ) ) {
		wp_send_json_error( array( 'message' => __( 'Permission denied.', 'tilvora-3d-flooring-visualizer' ) ) );
		return;
	}

	$id     = absint( $_POST['id'] ?? 0 );
	$status = sanitize_key( $_POST['status'] ?? '' );

	if ( ! $id || ! in_array( $status, array( 'new', 'replied', 'completed' ), true ) ) {
		wp_send_json_error( array( 'message' => __( 'Invalid request.', 'tilvora-3d-flooring-visualizer' ) ) );
		return;
	}

	$result = tilvora_update_quote_status( $id, $status );

	if ( false === $result ) {
		wp_send_json_error( array( 'message' => __( 'Could not update status.', 'tilvora-3d-flooring-visualizer' ) ) );
		return;
	}

	wp_send_json_success();
}

/* ── Page router ──────────────────────────────────────────────────────── */

function tilvora_render_quotes_page() {
	if ( ! current_user_can( 'manage_options' ) ) {
		wp_die( esc_html__( 'You do not have permission to view this page.', 'tilvora-3d-flooring-visualizer' ) );
	}

	// Delete / update_status / bulk actions are handled earlier, on "load-{$hook}"
	// (see tilvora_handle_quote_page_actions()) — has to happen before this
	// callback runs, since a redirect this late would fail (headers already sent).
	// Read-only routing below just picks which view to render; no nonce needed.
	// phpcs:disable WordPress.Security.NonceVerification.Recommended
	$action = sanitize_text_field( wp_unslash( $_GET['action'] ?? '' ) );

	// Show detail view.
	if ( 'view' === $action && ! empty( $_GET['id'] ) ) {
		tilvora_render_quote_detail( absint( $_GET['id'] ) );
		return;
	}
	// phpcs:enable WordPress.Security.NonceVerification.Recommended

	// Default: list table.
	tilvora_render_quote_list();
}

/* ── List table page ──────────────────────────────────────────────────── */

function tilvora_render_quote_list() {
	$table = new Tilvora_Quotes_List_Table();
	$table->prepare_items();

	$base_url = add_query_arg( array( 'page' => 'tilvora-quotes' ), admin_url( 'edit.php?post_type=' . TILVORA_CPT ) );

	echo '<div class="wrap">';
	echo '<h1 class="wp-heading-inline">' . esc_html__( 'Quote Inbox', 'tilvora-3d-flooring-visualizer' ) . '</h1>';
	echo '<hr class="wp-header-end">';

	// Admin notices — read-only GET params, no nonce needed for display.
	// phpcs:disable WordPress.Security.NonceVerification.Recommended
	if ( ! empty( $_GET['deleted'] ) ) {
		echo '<div class="notice notice-success is-dismissible"><p>' . esc_html__( 'Quote deleted.', 'tilvora-3d-flooring-visualizer' ) . '</p></div>';
	}

	// POST, not GET — the list table's bulk-action checkboxes (ids[]) are read from
	// $_POST by process_bulk_action(); a GET form would silently lose the selection.
	echo '<form method="post">';
	echo '<input type="hidden" name="post_type" value="' . esc_attr( TILVORA_CPT ) . '">';
	echo '<input type="hidden" name="page" value="tilvora-quotes">';
	if ( ! empty( $_GET['status'] ) ) {
		echo '<input type="hidden" name="status" value="' . esc_attr( sanitize_key( $_GET['status'] ) ) . '">';
	}
	// phpcs:enable WordPress.Security.NonceVerification.Recommended
	$table->search_box( __( 'Search quotes', 'tilvora-3d-flooring-visualizer' ), 'quote' );
	$table->views();
	$table->display();
	echo '</form>';
	echo '</div>';
}

/* ── Detail view ──────────────────────────────────────────────────────── */

function tilvora_render_quote_detail( $id ) {
	$quote = tilvora_get_quote( $id );
	if ( ! $quote ) {
		echo '<div class="wrap"><p>' . esc_html__( 'Quote not found.', 'tilvora-3d-flooring-visualizer' ) . '</p></div>';
		return;
	}

	$list_url    = add_query_arg( array( 'page' => 'tilvora-quotes' ), admin_url( 'edit.php?post_type=' . TILVORA_CPT ) );
	$current_status = sanitize_key( $quote->status );

	$status_labels = array(
		'new'       => __( 'New', 'tilvora-3d-flooring-visualizer' ),
		'replied'   => __( 'Replied', 'tilvora-3d-flooring-visualizer' ),
		'completed' => __( 'Completed', 'tilvora-3d-flooring-visualizer' ),
	);
	$status_label = $status_labels[ $current_status ] ?? esc_html( $current_status );

	$project_title = $quote->project_id ? get_the_title( $quote->project_id ) : '';

	echo '<div class="wrap fv-detail-wrap">';
	echo '<h1 class="wp-heading-inline">';
	/* translators: %s: customer name */
	echo esc_html( sprintf( __( 'Quote from %s', 'tilvora-3d-flooring-visualizer' ), $quote->customer_name ) );
	echo '</h1>';
	echo ' <a href="' . esc_url( $list_url ) . '" class="page-title-action">' . esc_html__( '&larr; All Quotes', 'tilvora-3d-flooring-visualizer' ) . '</a>';
	echo '<hr class="wp-header-end">';

	// Status bar.
	echo '<div class="fv-quote-status-bar">';
	echo '<strong>' . esc_html__( 'Status:', 'tilvora-3d-flooring-visualizer' ) . '</strong>';
	echo '<span class="fv-status-badge fv-status-' . esc_attr( $current_status ) . '" id="fv-badge-' . absint( $quote->id ) . '">' . esc_html( $status_label ) . '</span>';
	echo '<div class="fv-status-actions">';

	$statuses = array(
		'new'       => __( 'Mark New', 'tilvora-3d-flooring-visualizer' ),
		'replied'   => __( 'Mark Replied', 'tilvora-3d-flooring-visualizer' ),
		'completed' => __( 'Mark Completed', 'tilvora-3d-flooring-visualizer' ),
	);
	foreach ( $statuses as $slug => $label ) {
		$fallback_url = add_query_arg(
			array(
				'page'     => 'tilvora-quotes',
				'action'   => 'update_status',
				'id'       => $quote->id,
				'status'   => $slug,
				'_wpnonce' => wp_create_nonce( 'tilvora_status_' . $quote->id ),
			),
			admin_url( 'edit.php?post_type=' . TILVORA_CPT )
		);
		$is_current = ( $slug === $current_status );
		echo '<a href="' . esc_url( $fallback_url ) . '" class="fv-set-status' . ( $is_current ? ' is-current' : '' ) . '" data-id="' . absint( $quote->id ) . '" data-status="' . esc_attr( $slug ) . '">' . esc_html( $label ) . '</a>';
	}

	echo '</div>';
	echo '</div>';

	// Customer card.
	echo '<div class="fv-detail-card">';
	echo '<h3>' . esc_html__( 'Customer', 'tilvora-3d-flooring-visualizer' ) . '</h3>';
	tilvora_detail_row( __( 'Name', 'tilvora-3d-flooring-visualizer' ), $quote->customer_name );
	tilvora_detail_row( __( 'Email', 'tilvora-3d-flooring-visualizer' ), '<a href="mailto:' . esc_attr( $quote->customer_email ) . '">' . esc_html( $quote->customer_email ) . '</a>', false );
	if ( $quote->customer_phone ) {
		tilvora_detail_row( __( 'Phone', 'tilvora-3d-flooring-visualizer' ), $quote->customer_phone );
	}
	if ( $quote->customer_postcode ) {
		tilvora_detail_row( __( 'Postcode', 'tilvora-3d-flooring-visualizer' ), $quote->customer_postcode );
	}
	echo '</div>';

	// Design card.
	echo '<div class="fv-detail-card">';
	echo '<h3>' . esc_html__( 'Design Selection', 'tilvora-3d-flooring-visualizer' ) . '</h3>';

	if ( ! empty( $quote->design_image_url ) ) {
		echo '<div class="fv-design-image-wrap">';
		echo '<img src="' . esc_url( $quote->design_image_url ) . '" alt="' . esc_attr__( 'Customer design snapshot', 'tilvora-3d-flooring-visualizer' ) . '" />';
		echo '</div>';
		echo '<a class="fv-design-image-dl" href="' . esc_url( $quote->design_image_url ) . '" download>' . esc_html__( 'Download image', 'tilvora-3d-flooring-visualizer' ) . '</a>';
		echo '<hr style="margin:14px 0;border:none;border-top:1px solid #f0f0f0;">';
	}

	if ( $project_title ) {
		tilvora_detail_row( __( 'Project', 'tilvora-3d-flooring-visualizer' ), $project_title );
	}

	if ( ! empty( $quote->selection_summary ) ) {
		foreach ( explode( "\n", trim( $quote->selection_summary ) ) as $line ) {
			$parts = explode( ':', $line, 2 );
			if ( 2 === count( $parts ) ) {
				tilvora_detail_row( trim( $parts[0] ), trim( $parts[1] ) );
			} else {
				tilvora_detail_row( __( 'Selection', 'tilvora-3d-flooring-visualizer' ), $line );
			}
		}
	} else {
		// Legacy rows submitted before the selection_summary column existed.
		tilvora_detail_row( __( 'Tile', 'tilvora-3d-flooring-visualizer' ), $quote->tile_name ?: '—' );
		if ( $quote->finish_name ) {
			tilvora_detail_row( __( 'Finish', 'tilvora-3d-flooring-visualizer' ), $quote->finish_name );
		}
	}

	if ( ! empty( $quote->price_total ) ) {
		tilvora_detail_row( __( 'Price', 'tilvora-3d-flooring-visualizer' ), $quote->currency . $quote->price_total );
	}
	echo '</div>';

	// Room card.
	if ( $quote->room_width || $quote->room_height || $quote->room_area ) {
		echo '<div class="fv-detail-card">';
		echo '<h3>' . esc_html__( 'Room Dimensions', 'tilvora-3d-flooring-visualizer' ) . '</h3>';
		if ( $quote->room_width && $quote->room_height ) {
			tilvora_detail_row(
				__( 'Size', 'tilvora-3d-flooring-visualizer' ),
				esc_html( $quote->room_width ) . 'm &times; ' . esc_html( $quote->room_height ) . 'm',
				false
			);
		}
		if ( $quote->room_area ) {
			tilvora_detail_row( __( 'Area', 'tilvora-3d-flooring-visualizer' ), $quote->room_area );
		}
		if ( $quote->room_area_waste ) {
			tilvora_detail_row( __( 'Required (inc. waste)', 'tilvora-3d-flooring-visualizer' ), $quote->room_area_waste );
		}
		echo '</div>';
	}

	// Notes card.
	if ( $quote->notes ) {
		echo '<div class="fv-detail-card">';
		echo '<h3>' . esc_html__( 'Notes', 'tilvora-3d-flooring-visualizer' ) . '</h3>';
		echo '<p class="fv-detail-notes">' . esc_html( $quote->notes ) . '</p>';
		echo '</div>';
	}

	// Meta card.
	echo '<div class="fv-detail-card">';
	echo '<h3>' . esc_html__( 'Meta', 'tilvora-3d-flooring-visualizer' ) . '</h3>';
	$ts = strtotime( $quote->created_at );
	tilvora_detail_row(
		__( 'Received', 'tilvora-3d-flooring-visualizer' ),
		$ts ? date_i18n( get_option( 'date_format' ) . ' ' . get_option( 'time_format' ), $ts ) : esc_html( $quote->created_at )
	);
	tilvora_detail_row( __( 'Quote ID', 'tilvora-3d-flooring-visualizer' ), '#' . absint( $quote->id ) );
	echo '</div>';

	// Delete link.
	$delete_url = add_query_arg(
		array(
			'page'     => 'tilvora-quotes',
			'action'   => 'delete',
			'id'       => $quote->id,
			'_wpnonce' => wp_create_nonce( 'tilvora_delete_quote_' . $quote->id ),
		),
		admin_url( 'edit.php?post_type=' . TILVORA_CPT )
	);
	echo '<p>';
	echo '<a href="' . esc_url( $delete_url ) . '" class="submitdelete" onclick="return confirm(\'' . esc_js( __( 'Permanently delete this quote?', 'tilvora-3d-flooring-visualizer' ) ) . '\')">';
	echo esc_html__( 'Delete this quote', 'tilvora-3d-flooring-visualizer' );
	echo '</a>';
	echo '</p>';

	echo '</div>';
}

/**
 * Output a single label/value row inside a detail card.
 *
 * @param string $label  Label text (plain).
 * @param string $value  Value — auto-escaped unless $escape is false.
 * @param bool   $escape Whether to run esc_html on $value (default true).
 */
function tilvora_detail_row( $label, $value, $escape = true ) {
	echo '<div class="fv-detail-row">';
	echo '<span class="fv-detail-label">' . esc_html( $label ) . '</span>';
	echo '<span class="fv-detail-value">' . ( $escape ? esc_html( $value ) : $value ) . '</span>'; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped -- caller pre-escapes when $escape=false
	echo '</div>';
}

/* ── WP_List_Table subclass ───────────────────────────────────────────── */

if ( class_exists( 'WP_List_Table' ) ) :

class Tilvora_Quotes_List_Table extends WP_List_Table {

	public function __construct() {
		parent::__construct(
			array(
				'singular' => 'quote',
				'plural'   => 'quotes',
				'ajax'     => false,
			)
		);
	}

	public function get_columns() {
		return array(
			'cb'         => '<input type="checkbox" />',
			'customer'   => __( 'Customer', 'tilvora-3d-flooring-visualizer' ),
			'design'     => __( 'Selection', 'tilvora-3d-flooring-visualizer' ),
			'area'       => __( 'Room', 'tilvora-3d-flooring-visualizer' ),
			'project'    => __( 'Project', 'tilvora-3d-flooring-visualizer' ),
			'status'     => __( 'Status', 'tilvora-3d-flooring-visualizer' ),
			'created_at' => __( 'Received', 'tilvora-3d-flooring-visualizer' ),
		);
	}

	protected function get_sortable_columns() {
		return array(
			'customer'   => array( 'customer_name', false ),
			'status'     => array( 'status', false ),
			'created_at' => array( 'created_at', true ),
		);
	}

	protected function get_bulk_actions() {
		return array(
			'bulk_replied'   => __( 'Mark as Replied', 'tilvora-3d-flooring-visualizer' ),
			'bulk_completed' => __( 'Mark as Completed', 'tilvora-3d-flooring-visualizer' ),
			'bulk_delete'    => __( 'Delete', 'tilvora-3d-flooring-visualizer' ),
		);
	}

	protected function get_views() {
		$base        = add_query_arg( array( 'page' => 'tilvora-quotes' ), admin_url( 'edit.php?post_type=' . TILVORA_CPT ) );
		$current     = sanitize_key( $_REQUEST['status'] ?? '' ); // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- read-only view filter

		$counts = array(
			''          => tilvora_count_quotes(),
			'new'       => tilvora_count_quotes( 'new' ),
			'replied'   => tilvora_count_quotes( 'replied' ),
			'completed' => tilvora_count_quotes( 'completed' ),
		);

		$view_labels = array(
			''          => __( 'All', 'tilvora-3d-flooring-visualizer' ),
			'new'       => __( 'New', 'tilvora-3d-flooring-visualizer' ),
			'replied'   => __( 'Replied', 'tilvora-3d-flooring-visualizer' ),
			'completed' => __( 'Completed', 'tilvora-3d-flooring-visualizer' ),
		);

		$views = array();
		foreach ( $view_labels as $slug => $label ) {
			$url        = $slug ? add_query_arg( 'status', $slug, $base ) : $base;
			$is_current = ( $slug === $current );
			$views[ $slug ?: 'all' ] = sprintf(
				'<a href="%s"%s>%s <span class="count">(%s)</span></a>',
				esc_url( $url ),
				$is_current ? ' class="current" aria-current="page"' : '',
				esc_html( $label ),
				absint( $counts[ $slug ] )
			);
		}
		return $views;
	}

	protected function column_cb( $item ) {
		return '<input type="checkbox" name="ids[]" value="' . absint( $item->id ) . '" />';
	}

	protected function column_customer( $item ) {
		$view_url   = add_query_arg(
			array( 'page' => 'tilvora-quotes', 'action' => 'view', 'id' => $item->id ),
			admin_url( 'edit.php?post_type=' . TILVORA_CPT )
		);
		$delete_url = add_query_arg(
			array(
				'page'     => 'tilvora-quotes',
				'action'   => 'delete',
				'id'       => $item->id,
				'_wpnonce' => wp_create_nonce( 'tilvora_delete_quote_' . $item->id ),
			),
			admin_url( 'edit.php?post_type=' . TILVORA_CPT )
		);

		$actions = array(
			'view'   => '<a href="' . esc_url( $view_url ) . '">' . __( 'View', 'tilvora-3d-flooring-visualizer' ) . '</a>',
			'delete' => '<a href="' . esc_url( $delete_url ) . '" onclick="return confirm(\'' . esc_js( __( 'Delete this quote?', 'tilvora-3d-flooring-visualizer' ) ) . '\')">' . __( 'Delete', 'tilvora-3d-flooring-visualizer' ) . '</a>',
		);

		$out  = '<a href="' . esc_url( $view_url ) . '"><strong>' . esc_html( $item->customer_name ) . '</strong></a>';
		$out .= '<br><span class="description">' . esc_html( $item->customer_email ) . '</span>';
		if ( $item->customer_phone ) {
			$out .= '<br><span class="description">' . esc_html( $item->customer_phone ) . '</span>';
		}

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

	protected function column_design( $item ) {
		$out = '';

		if ( ! empty( $item->design_image_url ) ) {
			$view_url = add_query_arg(
				array( 'page' => 'tilvora-quotes', 'action' => 'view', 'id' => $item->id ),
				admin_url( 'edit.php?post_type=' . TILVORA_CPT )
			);
			$out .= '<a href="' . esc_url( $view_url ) . '">'
				. '<img class="fv-design-thumb" src="' . esc_url( $item->design_image_url ) . '" alt="' . esc_attr__( 'Design preview', 'tilvora-3d-flooring-visualizer' ) . '" loading="lazy" />'
				. '</a>';
		}

		if ( ! empty( $item->selection_summary ) ) {
			$lines = explode( "\n", trim( $item->selection_summary ) );
			$out  .= '<strong>' . esc_html( $lines[0] ) . '</strong>';
			for ( $i = 1, $len = count( $lines ); $i < $len; $i++ ) {
				$out .= '<br><span class="description">' . esc_html( $lines[ $i ] ) . '</span>';
			}
		} elseif ( $item->tile_name ) {
			// Legacy rows submitted before the selection_summary column existed.
			$out .= '<strong>' . esc_html( $item->tile_name ) . '</strong>';
			if ( $item->finish_name ) {
				$out .= '<br><span class="description">' . esc_html( $item->finish_name ) . '</span>';
			}
		}

		if ( ! empty( $item->price_total ) ) {
			$out .= ( $out ? '<br>' : '' ) . '<strong style="color:#2271b1">' . esc_html( $item->currency . $item->price_total ) . '</strong>';
		}

		return $out ?: '&mdash;';
	}

	protected function column_area( $item ) {
		if ( ! $item->room_width || ! $item->room_height ) {
			return '&mdash;';
		}
		$out = esc_html( $item->room_width ) . 'm &times; ' . esc_html( $item->room_height ) . 'm';
		if ( $item->room_area_waste ) {
			$out .= '<br><span class="description">' . esc_html( $item->room_area_waste ) . ' ' . esc_html__( '(inc. waste)', 'tilvora-3d-flooring-visualizer' ) . '</span>';
		}
		return $out;
	}

	protected function column_project( $item ) {
		if ( ! $item->project_id ) {
			return '&mdash;';
		}
		$title = get_the_title( $item->project_id );
		return $title ? esc_html( $title ) : '&mdash;';
	}

	protected function column_status( $item ) {
		$current = sanitize_key( $item->status );
		$labels  = array(
			'new'       => __( 'New', 'tilvora-3d-flooring-visualizer' ),
			'replied'   => __( 'Replied', 'tilvora-3d-flooring-visualizer' ),
			'completed' => __( 'Completed', 'tilvora-3d-flooring-visualizer' ),
		);
		$label = $labels[ $current ] ?? esc_html( $current );

		$out = '<span class="fv-status-badge fv-status-' . esc_attr( $current ) . '" id="fv-badge-' . absint( $item->id ) . '">' . esc_html( $label ) . '</span>';

		// Status-change links (AJAX-enhanced, GET-link fallback).
		$out .= '<div class="fv-status-actions">';
		$change_statuses = array(
			'new'       => __( 'New', 'tilvora-3d-flooring-visualizer' ),
			'replied'   => __( 'Replied', 'tilvora-3d-flooring-visualizer' ),
			'completed' => __( 'Completed', 'tilvora-3d-flooring-visualizer' ),
		);
		foreach ( $change_statuses as $slug => $change_label ) {
			$fallback_url = add_query_arg(
				array(
					'page'     => 'tilvora-quotes',
					'action'   => 'update_status',
					'id'       => $item->id,
					'status'   => $slug,
					'_wpnonce' => wp_create_nonce( 'tilvora_status_' . $item->id ),
				),
				admin_url( 'edit.php?post_type=' . TILVORA_CPT )
			);
			$is_current = ( $slug === $current );
			$out .= '<a href="' . esc_url( $fallback_url ) . '" class="fv-set-status' . ( $is_current ? ' is-current' : '' ) . '" data-id="' . absint( $item->id ) . '" data-status="' . esc_attr( $slug ) . '">' . esc_html( $change_label ) . '</a>';
		}
		$out .= '</div>';

		return $out;
	}

	protected function column_created_at( $item ) {
		$ts = strtotime( $item->created_at );
		if ( ! $ts ) {
			return '&mdash;';
		}
		$formatted = date_i18n( get_option( 'date_format' ), $ts );
		return '<span title="' . esc_attr( date_i18n( 'Y-m-d H:i', $ts ) ) . '">' . esc_html( $formatted ) . '</span>';
	}

	protected function column_default( $item, $column_name ) {
		return isset( $item->$column_name ) ? esc_html( $item->$column_name ) : '';
	}

	public function prepare_items() {
		$this->_column_headers = array( $this->get_columns(), array(), $this->get_sortable_columns() );

		// Process bulk actions before fetching rows.
		$this->process_bulk_action();

		$per_page = 20;
		// phpcs:disable WordPress.Security.NonceVerification.Recommended -- WP_List_Table pagination/sort/filter params; read-only admin view.
		$orderby  = sanitize_key( $_REQUEST['orderby'] ?? 'created_at' );
		$order    = sanitize_key( $_REQUEST['order']   ?? 'desc' );
		$status   = sanitize_key( $_REQUEST['status']  ?? '' );
		$search   = sanitize_text_field( wp_unslash( $_REQUEST['s'] ?? '' ) );
		$paged    = max( 1, absint( $_REQUEST['paged'] ?? 1 ) );
		// phpcs:enable WordPress.Security.NonceVerification.Recommended

		$args = array(
			'status'  => $status,
			'search'  => $search,
			'orderby' => $orderby,
			'order'   => strtoupper( $order ),
			'limit'   => $per_page,
			'offset'  => ( $paged - 1 ) * $per_page,
		);

		$this->items = tilvora_get_quotes( $args );
		$total       = tilvora_count_quotes_filtered( $args );

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

	public function process_bulk_action() {
		$action = $this->current_action();
		if ( ! $action ) {
			return;
		}
		if ( ! in_array( $action, array( 'bulk_replied', 'bulk_completed', 'bulk_delete' ), true ) ) {
			return;
		}

		check_admin_referer( 'bulk-quotes' );

		$ids = array_filter( array_map( 'absint', (array) ( $_POST['ids'] ?? array() ) ) );
		if ( ! $ids ) {
			return;
		}

		if ( 'bulk_delete' === $action ) {
			tilvora_delete_quotes( $ids );
		} elseif ( 'bulk_replied' === $action ) {
			foreach ( $ids as $id ) {
				tilvora_update_quote_status( $id, 'replied' );
			}
		} elseif ( 'bulk_completed' === $action ) {
			foreach ( $ids as $id ) {
				tilvora_update_quote_status( $id, 'completed' );
			}
		}

		wp_safe_redirect(
			remove_query_arg(
				array( 'action', 'action2', 'ids', '_wpnonce', '_wp_http_referer' ),
				wp_get_referer()
			)
		);
		exit;
	}
}

endif; // class_exists( 'WP_List_Table' )
