<?php
/**
 * Vehicles list screen built on WP_List_Table.
 *
 * Renders active vehicles (status = 'active') read from the repository. Each row
 * resolves its owning customer to a display name through the customers
 * repository. Sorting links and the search box are rendered here; their
 * server-side handling runs through the repository sortable map and LIKE search.
 *
 * @package WrenchPress
 */

defined( 'ABSPATH' ) || exit;

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

/**
 * Class WrenchPress_Vehicles_List_Table
 */
class WrenchPress_Vehicles_List_Table extends WP_List_Table {

	/**
	 * Admin page slug the row actions link back to.
	 */
	const PAGE_SLUG = 'wrenchpress-vehicles';

	/**
	 * Per-request cache of resolved customer display names, keyed by id, so the
	 * list does not re-query the same owner once per row.
	 *
	 * @var array<int,string>
	 */
	private $customer_names = array();

	/**
	 * Configure the list table.
	 */
	public function __construct() {
		parent::__construct(
			array(
				'singular' => 'vehicle',
				'plural'   => 'vehicles',
				'ajax'     => false,
			)
		);
	}

	/**
	 * Visible columns.
	 *
	 * @return array<string,string>
	 */
	public function get_columns() {
		return array(
			'vehicle'    => __( 'Vehicle', 'pitdesk-repair-crm' ),
			'customer'   => __( 'Customer', 'pitdesk-repair-crm' ),
			'plate'      => __( 'Plate', 'pitdesk-repair-crm' ),
			'mileage'    => __( 'Mileage', 'pitdesk-repair-crm' ),
			'updated_at' => __( 'Last updated', 'pitdesk-repair-crm' ),
		);
	}

	/**
	 * Sortable columns. The request key matches the repository sortable map.
	 *
	 * @return array<string,array{0:string,1:bool}>
	 */
	public function get_sortable_columns() {
		return array(
			'vehicle'    => array( 'vehicle', false ),
			'updated_at' => array( 'created_at', false ),
		);
	}

	/**
	 * Vehicle is the primary column (carries the row actions).
	 *
	 * @return string
	 */
	protected function get_default_primary_column_name() {
		return 'vehicle';
	}

	/**
	 * Empty-state copy. Differentiates "no vehicles at all" from "no search
	 * match".
	 *
	 * @return void
	 */
	public function no_items() {
		$search = isset( $_REQUEST['s'] ) ? sanitize_text_field( wp_unslash( $_REQUEST['s'] ) ) : ''; // phpcs:ignore WordPress.Security.NonceVerification.Recommended

		if ( '' !== $search ) {
			esc_html_e( 'No vehicles found matching your search.', 'pitdesk-repair-crm' );
			return;
		}

		echo '<strong>' . esc_html__( 'No vehicles yet', 'pitdesk-repair-crm' ) . '</strong><br />';
		echo esc_html__( 'Add a vehicle and link it to a customer to start tracking its service history.', 'pitdesk-repair-crm' );

		if ( current_user_can( WrenchPress_Capabilities::CREATE_VEHICLES ) ) {
			$add_url = add_query_arg(
				array(
					'page'   => self::PAGE_SLUG,
					'action' => 'add',
				),
				admin_url( 'admin.php' )
			);
			echo ' <a href="' . esc_url( $add_url ) . '" class="button button-primary">' . esc_html__( 'Add Vehicle', 'pitdesk-repair-crm' ) . '</a>';
		}
	}

	/**
	 * Render the Vehicle column as "Year Make Model" with row actions.
	 *
	 * @param object $item Vehicle row.
	 * @return string
	 */
	public function column_vehicle( $item ) {
		$display = self::vehicle_label( $item );
		$base    = admin_url( 'admin.php' );
		$actions = array();

		if ( current_user_can( WrenchPress_Capabilities::EDIT_VEHICLES ) ) {
			$edit_url        = add_query_arg(
				array(
					'page'    => self::PAGE_SLUG,
					'action'  => 'edit',
					'vehicle' => (int) $item->id,
				),
				$base
			);
			$actions['edit'] = '<a href="' . esc_url( $edit_url ) . '">' . esc_html__( 'Edit', 'pitdesk-repair-crm' ) . '</a>';
		}

		$view_url        = add_query_arg(
			array(
				'page'    => self::PAGE_SLUG,
				'action'  => 'view',
				'vehicle' => (int) $item->id,
			),
			$base
		);
		$actions['view'] = '<a href="' . esc_url( $view_url ) . '">' . esc_html__( 'View', 'pitdesk-repair-crm' ) . '</a>';

		if ( current_user_can( WrenchPress_Capabilities::DELETE_VEHICLES ) ) {
			$archive_url        = wp_nonce_url(
				add_query_arg(
					array(
						'page'    => self::PAGE_SLUG,
						'action'  => 'archive',
						'vehicle' => (int) $item->id,
					),
					$base
				),
				'wrenchpress_archive_vehicle_' . (int) $item->id
			);
			$actions['archive'] = '<a href="' . esc_url( $archive_url ) . '" class="submitdelete">' . esc_html__( 'Archive', 'pitdesk-repair-crm' ) . '</a>';
		}

		return '<strong>' . esc_html( $display ) . '</strong>' . $this->row_actions( $actions );
	}

	/**
	 * Render non-primary columns with escaped output.
	 *
	 * @param object $item        Vehicle row.
	 * @param string $column_name Column key.
	 * @return string
	 */
	public function column_default( $item, $column_name ) {
		switch ( $column_name ) {
			case 'customer':
				return esc_html( $this->customer_name( (int) $item->customer_id ) );

			case 'plate':
				return esc_html( (string) $item->plate );

			case 'mileage':
				$mileage = (int) $item->mileage;

				if ( $mileage <= 0 ) {
					return '';
				}

				$unit    = WrenchPress_Settings_Page::mileage_unit();
				$display = WrenchPress_Reminders_Repository::mileage_to_display( $mileage, $unit );

				return esc_html( number_format_i18n( $display ) . ' ' . $unit );

			case 'updated_at':
				$timestamp = strtotime( (string) $item->updated_at );
				return $timestamp ? esc_html( date_i18n( get_option( 'date_format' ), $timestamp ) ) : '';

			default:
				return '';
		}
	}

	/**
	 * Compose the human-readable vehicle label from year, make, and model.
	 *
	 * @param object $item Vehicle row.
	 * @return string
	 */
	public static function vehicle_label( $item ) {
		$parts = array();

		if ( ! empty( $item->year ) ) {
			$parts[] = (string) (int) $item->year;
		}

		if ( '' !== (string) $item->make ) {
			$parts[] = (string) $item->make;
		}

		if ( '' !== (string) $item->model ) {
			$parts[] = (string) $item->model;
		}

		$label = trim( implode( ' ', $parts ) );

		return '' !== $label ? $label : __( '(unnamed vehicle)', 'pitdesk-repair-crm' );
	}

	/**
	 * Resolve a customer id to a "Last, First" display name, cached per request.
	 *
	 * @param int $customer_id Owning customer id.
	 * @return string
	 */
	private function customer_name( $customer_id ) {
		$customer_id = (int) $customer_id;

		if ( 0 === $customer_id ) {
			return '';
		}

		if ( isset( $this->customer_names[ $customer_id ] ) ) {
			return $this->customer_names[ $customer_id ];
		}

		$customer = WrenchPress_Customers_Repository::get( $customer_id );

		if ( $customer ) {
			$name = trim( sprintf( '%s, %s', $customer->last_name, $customer->first_name ), ', ' );
		} else {
			$name = '';
		}

		$this->customer_names[ $customer_id ] = $name;

		return $name;
	}

	/**
	 * Query active vehicles and configure pagination and column headers.
	 *
	 * @return void
	 */
	public function prepare_items() {
		$per_page     = 20;
		$current_page = $this->get_pagenum();
		$offset       = ( $current_page - 1 ) * $per_page;

		// phpcs:disable WordPress.Security.NonceVerification.Recommended -- read-only list filters from a GET request.
		$search  = isset( $_REQUEST['s'] ) ? sanitize_text_field( wp_unslash( $_REQUEST['s'] ) ) : '';
		$orderby = isset( $_REQUEST['orderby'] ) ? sanitize_key( wp_unslash( $_REQUEST['orderby'] ) ) : 'vehicle';
		$order   = ( isset( $_REQUEST['order'] ) && 'desc' === strtolower( sanitize_key( wp_unslash( $_REQUEST['order'] ) ) ) ) ? 'DESC' : 'ASC';
		// phpcs:enable WordPress.Security.NonceVerification.Recommended

		// Whitelist the orderby key against the repository sortable map; unknown
		// keys fall back to the default order inside the repository.
		if ( ! array_key_exists( $orderby, WrenchPress_Vehicles_Repository::sortable_map() ) ) {
			$orderby = 'vehicle';
		}

		$args = array(
			'search'   => $search,
			'orderby'  => $orderby,
			'order'    => $order,
			'per_page' => $per_page,
			'offset'   => $offset,
		);

		$this->items = WrenchPress_Vehicles_Repository::list_active( $args );

		$total = WrenchPress_Vehicles_Repository::count_active( array( 'search' => $search ) );

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

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