<?php
/**
 * Data Display trait
 *
 * @package     AffiliateWP
 * @subpackage  Utils\Traits
 * @copyright   Copyright (c) 2026, Sandhills Development, LLC
 * @license     http://opensource.org/licenses/gpl-2.0.php GNU Public License
 * @since       2.33.0
 */

namespace AffiliateWP\Utils\Traits;

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

/**
 * Data Display trait
 *
 * Reusable label/value list and tabular display primitives used across
 * admin surfaces (payout drawer details extras, affiliate panels, reports).
 * Matches the drawer's native label/value pattern so contributor content
 * sits visually alongside core fields without ad-hoc Tailwind copy-paste.
 *
 * @since 2.33.0
 */
trait Data_Display {

	/**
	 * Render a vertical label/value property list.
	 *
	 * @since 2.33.0
	 *
	 * @param array $args {
	 *     @type array  $properties Associative array of label => value pairs, OR
	 *                              array of [ 'label' => string, 'value' => string|array ].
	 *                              Values are esc_html'd by default; pass an array with an
	 *                              'html' key to emit pre-sanitized HTML (e.g. links).
	 *     @type string $class      Extra container classes. Optional.
	 *     @type string $id         Container id attribute. Optional.
	 * }
	 * @return string Rendered HTML, or empty string if no properties.
	 */
	public function render_property_list( $args = [] ) {

		$defaults = [
			'properties' => [],
			'class'      => '',
			'id'         => '',
		];
		$args = wp_parse_args( $args, $defaults );

		if ( empty( $args['properties'] ) || ! is_array( $args['properties'] ) ) {
			return '';
		}

		$container_class = trim( 'affwp-property-list flex flex-col gap-3 text-sm ' . (string) $args['class'] );

		$id_attr = '' !== (string) $args['id'] ? sprintf( ' id="%s"', esc_attr( (string) $args['id'] ) ) : '';

		$rows = '';

		foreach ( $args['properties'] as $key => $entry ) {

			if ( is_array( $entry ) && isset( $entry['label'] ) ) {
				$label = (string) $entry['label'];
				$value = $entry['value'] ?? '';
			} else {
				$label = (string) $key;
				$value = $entry;
			}

			$value_html = is_array( $value ) && isset( $value['html'] )
				? (string) $value['html']
				: esc_html( (string) $value );

			$rows .= sprintf(
				'<div class="flex items-baseline justify-between gap-3"><dt class="text-gray-500">%1$s</dt><dd class="text-gray-900 text-right">%2$s</dd></div>',
				esc_html( $label ),
				$value_html
			);
		}

		return sprintf( '<dl class="%1$s"%2$s>%3$s</dl>', esc_attr( $container_class ), $id_attr, $rows );
	}

	/**
	 * Render a multi-column data table.
	 *
	 * @since 2.33.0
	 *
	 * @param array $args {
	 *     @type array  $columns Array of column defs: [ 'key' => string, 'label' => string,
	 *                           'class' => string (per-column cell class). ].
	 *     @type array  $rows    Array of row data, each a map keyed by column 'key'. Cell
	 *                           values are esc_html'd; pass [ 'html' => '...' ] for pre-
	 *                           sanitized HTML.
	 *     @type bool   $striped Add zebra striping. Default false.
	 *     @type string $empty   Text to show when rows is empty. Default '— No data —'.
	 *     @type string $class   Extra <table> classes. Optional.
	 *     @type string $id      <table> id attribute. Optional.
	 * }
	 * @return string Rendered HTML.
	 */
	public function render_data_table( $args = [] ) {

		$defaults = [
			'columns' => [],
			'rows'    => [],
			'striped' => false,
			'empty'   => __( '— No data —', 'affiliate-wp' ),
			'class'   => '',
			'id'      => '',
		];
		$args = wp_parse_args( $args, $defaults );

		if ( empty( $args['columns'] ) || ! is_array( $args['columns'] ) ) {
			return '';
		}

		$table_class = trim( 'affwp-data-table w-full text-sm ' . (string) $args['class'] );

		$id_attr = '' !== (string) $args['id'] ? sprintf( ' id="%s"', esc_attr( (string) $args['id'] ) ) : '';

		$head = '<thead><tr class="border-b border-gray-200">';
		foreach ( $args['columns'] as $col ) {
			$head .= sprintf(
				'<th class="text-left text-gray-500 font-medium px-3 py-2 whitespace-nowrap">%s</th>',
				esc_html( (string) ( $col['label'] ?? '' ) )
			);
		}
		$head .= '</tr></thead>';

		$body  = '<tbody>';
		$count = is_array( $args['rows'] ) ? count( $args['rows'] ) : 0;

		if ( 0 === $count ) {
			$body .= sprintf(
				'<tr><td class="px-3 py-2 text-gray-500 italic" colspan="%1$d">%2$s</td></tr>',
				count( $args['columns'] ),
				esc_html( (string) $args['empty'] )
			);
		} else {
			foreach ( $args['rows'] as $i => $row ) {
				$row_class = 'border-b border-gray-100';
				if ( $args['striped'] && ( $i % 2 ) === 1 ) {
					$row_class .= ' bg-gray-50';
				}
				$body .= sprintf( '<tr class="%s">', esc_attr( $row_class ) );
				foreach ( $args['columns'] as $col ) {
					$key       = (string) ( $col['key'] ?? '' );
					$cell      = $row[ $key ] ?? '';
					$cell_html = is_array( $cell ) && isset( $cell['html'] )
						? (string) $cell['html']
						: esc_html( (string) $cell );
					$cell_class = trim( 'px-3 py-2 whitespace-nowrap ' . (string) ( $col['class'] ?? '' ) );
					$body .= sprintf( '<td class="%1$s">%2$s</td>', esc_attr( $cell_class ), $cell_html );
				}
				$body .= '</tr>';
			}
		}
		$body .= '</tbody>';

		// Wrap in overflow-x-auto so wide tables scroll horizontally instead of pushing the drawer width.
		return sprintf(
			'<div class="overflow-x-auto"><table class="%1$s"%2$s>%3$s%4$s</table></div>',
			esc_attr( $table_class ),
			$id_attr,
			$head,
			$body
		);
	}
}
