<?php
/**
 * Referrals list table view.
 *
 * @package Awesomemotive\Rewardswp\Views\Admin\ListTables
 * @since 1.0.0
 */

namespace Awesomemotive\Rewardswp\Views\Admin\ListTables;

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

use Awesomemotive\Rewardswp\Factories\IntegrationsFactory;
use Awesomemotive\Rewardswp\Interfaces\IntegrationInterface;
use Awesomemotive\Rewardswp\Interfaces\IntegrationWithCouponInterface;
use Awesomemotive\Rewardswp\Interfaces\ViewInterface;
use Awesomemotive\Rewardswp\Models\Member;
use Awesomemotive\Rewardswp\Models\Referral;
use Awesomemotive\Rewardswp\Services\ReferralsService;
use Awesomemotive\Rewardswp\Services\MembersService;
use Exception;
use WP_List_Table;
use function Awesomemotive\Rewardswp\Helpers\get_member;
use function Awesomemotive\Rewardswp\Helpers\get_human_readable_date;
use function Awesomemotive\Rewardswp\Helpers\get_user_full_name;
use function Awesomemotive\Rewardswp\Helpers\kses;

class ReferralsListTableView extends WP_List_Table implements ViewInterface {
	/**
	 * The gravatar size.
	 *
	 * @since 1.0.0
	 *
	 * @var int
	 */
	const GRAVATAR_SIZE = 36;

	/**
	 * Referrals service instance.
	 *
	 * @since 1.0.0
	 *
	 * @var ReferralsService
	 */
	private ReferralsService $referrals_service;

	/**
	 * Integrations factory instance.
	 *
	 * @since 1.0.0
	 *
	 * @var IntegrationsFactory
	 */
	private IntegrationsFactory $integration_factory;

	/**
	 * Members service instance.
	 *
	 * @since 1.0.0
	 *
	 * @var MembersService
	 */
	private MembersService $members_service;

	/**
	 * Status labels for list table.
	 *
	 * @since 1.0.0
	 *
	 * @var array
	 */
	private array $statuses = [];

	/**
	 * Constructor.
	 *
	 * @param ReferralsService    $referrals_service
	 * @param IntegrationsFactory $integration_factory
	 * @param MembersService      $members_service
	 *
	 * @since 1.0.0
	 */
	public function __construct(
		ReferralsService $referrals_service,
		IntegrationsFactory $integration_factory,
		MembersService $members_service
	) {
		$this->referrals_service   = $referrals_service;
		$this->integration_factory = $integration_factory;
		$this->members_service     = $members_service;

		$this->statuses = [
			'completed' => esc_html__( 'Completed', 'rewardswp' ),
			'canceled'  => esc_html__( 'Canceled', 'rewardswp' ),
			'pending'   => esc_html__( 'Pending', 'rewardswp' ),
			'blocked'   => esc_html__( 'Blocked', 'rewardswp' ),
		];

		parent::__construct(
			[
				'singular' => 'referral',
				'plural'   => 'referrals',
				'ajax'     => false,
			]
		);
	}

	/**
	 * Get columns.
	 *
	 * @since 1.0.0
	 *
	 * @return array
	 */
	public function get_columns(): array {
		return [
			'referred'    => esc_html__( 'Referred Friend', 'rewardswp' ),
			'member'      => esc_html__( 'Referring Advocate', 'rewardswp' ),
			'order_total' => esc_html__( 'Order Total', 'rewardswp' ),
			'status'      => esc_html__( 'Status', 'rewardswp' ),
			'created_at'  => esc_html__( 'Date Created', 'rewardswp' ),
		];
	}

	/**
	 * Get sortable columns.
	 *
	 * @since 1.0.0
	 *
	 * @return array
	 */
	public function get_sortable_columns(): array {
		return [
			'status'     => [ 'status', false ],
			'created_at' => [ 'created_at', false ],
		];
	}

	/**
	 * Set hidden columns.
	 *
	 * @since 1.0.0
	 *
	 * @return array
	 */
	public function get_hidden_columns(): array {
		return get_hidden_columns( $this->screen );
	}

	/**
	 * Get bulk actions.
	 *
	 * @since 1.0.0
	 *
	 * @return array
	 */
	public function get_bulk_actions(): array {
		return [];
	}

	/**
	 * Renders the message to be displayed when there are no referrals.
	 *
	 * @since 1.0.0
	 */
	function no_items() {
		esc_html_e( 'No Referrals found.', 'rewardswp' );
	}

	/**
	 * Parse query arguments for referrals search and filtering.
	 *
	 * @since 1.0.0
	 *
	 * @return array Parsed query arguments ready for ReferralsService.
	 */
	private function parse_query_args(): array {
		$args = array_filter(
			[
				'order'   => sanitize_text_field( filter_input( INPUT_GET, 'order' ) ?? 'desc' ),
				'orderby' => sanitize_text_field( filter_input( INPUT_GET, 'orderby' ) ?? 'id' ),
				'status'  => sanitize_text_field( filter_input( INPUT_GET, 'status' ) ?? '' ),
			]
		);

		// Handle search query by member (advocate or friend)
		$search_term = sanitize_text_field( filter_input( INPUT_GET, 's' ) ?? '' );
		if ( ! empty( $search_term ) ) {
			// Search for members (advocates) using MembersService
			$members = $this->members_service->get_members(
				[
					'like_query' => [
						'search_term' => $search_term,
						'columns'     => [
							'first_name',
							'last_name',
							'email',
							"CONCAT(first_name, ' ', last_name)",
						],
						'compare'     => 'OR',
					],
				],
				9999, // Get all matching members
				1
			);

			if ( ! empty( $members ) ) {
				// Found members, search by advocate_id
				$member_ids          = array_map(
					function ( $member ) {
						return $member->id;
					},
					$members
				);
				$args['advocate_id'] = $member_ids;
			} else {
				// No members found, try searching by referred_email directly
				$args['like_query'] = [
					'search_term' => $search_term,
					'columns'     => [
						'referred_email',
					],
					'compare'     => 'OR',
				];
			}
		}

		return $args;
	}

	/**
	 * Prepare items.
	 *
	 * @since 1.0.0
	 *
	 * @param int $per_page The number of items per page. Default 20.
	 *
	 * @return void
	 */
	public function prepare_items( int $per_page = 20 ): void {
		$this->_column_headers = [
			$this->get_columns(),
			$this->get_hidden_columns(),
			$this->get_sortable_columns(),
		];

		$current_page = $this->get_pagenum();
		$query_args   = $this->parse_query_args();

		// Get total count for pagination
		$total_count = $this->referrals_service->count_referrals( $query_args );

		$this->set_pagination_args(
			[
				'total_items' => $total_count,
				'total_pages' => ceil( $total_count / $per_page ),
				'per_page'    => $per_page,
			]
		);

		// Get the referrals data
		$this->items = $this->referrals_service->get_referrals(
			$query_args,
			$per_page,
			$current_page
		);
	}

	/**
	 * Render the template.
	 *
	 * @since 1.0.0
	 *
	 * @param array $args {
	 *     @type string $page_title     The page title. Default to the current admin page title.
	 *     @type string $items_per_page The page content. Default ''.
	 * }
	 *
	 * @return void
	 */
	public function render( array $args = [] ): void {
		$args = wp_parse_args(
			$args,
			[
				'page_title'     => esc_html__( 'Referrals', 'rewardswp' ),
				'items_per_page' => $this->get_items_per_page( 'referrals_per_page' ),
			]
		);

		$this->prepare_items( $args['items_per_page'] );

		?>

		<div class="mt-6 mr-6 mb-0 ml-[2px] px-3">

			<div class="rewardswp-container sr-only">
				<div class="flex flex-col gap-4 md:flex-row md:items-start md:justify-between">
					<h1 class="text-2xl text-slate-900"><?php echo esc_html( $args['page_title'] ); ?></h1>
				</div>
			</div>

			<div class="mb-0" style="overflow: hidden;">
				<?php
				$this->views();
				?>
			</div>

			<form method="get">
				<?php
				// Preserve current page and other query parameters
				// This is an admin GET form for navigation purposes only, nonce verification is not required.
				// phpcs:ignore WordPress.Security.NonceVerification.Recommended
				foreach ( $_GET as $key => $value ) {
					if ( 'page' === $key || 'paged' === $key || 's' === $key ) {
						continue; // These will be handled by search_box() and pagination
					}
					// Sanitize the value for output in hidden field.
					$sanitized_key   = sanitize_text_field( wp_unslash( $key ) );
					$sanitized_value = sanitize_text_field( wp_unslash( $value ) );
					echo '<input type="hidden" name="' . esc_attr( $sanitized_key ) . '" value="' . esc_attr( $sanitized_value ) . '" />';
				}
				// phpcs:ignore WordPress.Security.NonceVerification.Recommended
				$current_page = isset( $_GET['page'] ) ? sanitize_text_field( wp_unslash( $_GET['page'] ) ) : '';
				echo '<input type="hidden" name="page" value="' . esc_attr( $current_page ) . '" />';
				?>
				<?php $this->search_box( esc_html__( 'Search Referrals', 'rewardswp' ), 'search_id' ); ?>
				<?php $this->display_tablenav( 'top' ); ?>

				<table class="wp-list-table <?php echo esc_attr( implode( ' ', $this->get_table_classes() ) ); ?>">

					<thead>
						<tr>
							<?php $this->print_column_headers(); ?>
						</tr>
					</thead>

					<tbody id="the-list" <?php echo $this->has_items() ? 'data-wp-lists="list:' . esc_attr( $this->_args['singular'] ) . '"' : ''; ?>>
						<?php $this->display_rows_or_placeholder(); ?>
					</tbody>

					<tfoot>
						<tr>
							<?php $this->print_column_headers( false ); ?>
						</tr>
					</tfoot>

				</table>

				<?php $this->display_tablenav( 'bottom' ); ?>

			</form>
		</div>
		<?php
	}

	/**
	 * Column cb.
	 *
	 * @since 1.0.0
	 *
	 * @param Referral $item Referral object.
	 *
	 * @return string
	 */
	public function column_cb( $item ): string {
		return sprintf(
			'<input type="checkbox" name="bulk-delete[]" value="%s" />',
			$item->id
		);
	}

	/**
	 * Column default.
	 *
	 * @param Referral $item        Referral object.
	 * @param string   $column_name Column name.
	 *
	 * @return string
	 *
	 * @throws Exception
	 */
	public function column_default( $item, $column_name ): string {
		switch ( $column_name ) {
			case 'id':
				return esc_html( $item->$column_name );
			case 'status':
				$status_classes = [
					'completed' => 'bg-green-50 text-green-700 ring-green-600/20',
					'canceled'  => 'bg-gray-50 text-gray-600 ring-gray-500/20',
					'blocked'   => 'bg-red-50 text-red-700 ring-red-600/20',
					'pending'   => 'bg-yellow-50 text-yellow-700 ring-yellow-600/20',
				];

				$status_key = strtolower( $item->status );
				$classes    = $status_classes[ $status_key ] ?? 'bg-gray-50 text-gray-600 ring-gray-500/20';

				return sprintf(
					'<span class="inline-flex items-center rounded-md px-2 py-1 text-xs font-medium ring-1 ring-inset %s">%s</span>',
					esc_attr( $classes ),
					esc_html( $this->statuses[ $item->status ] )
				);
			case 'created_at':
				return get_human_readable_date( $item->created_at, true );
			case 'member':
				$advocate = get_member( $item->advocate_id );

				if ( ! is_a( $advocate, Member::class ) ) {
					return esc_html__( 'N/A', 'rewardswp' );
				}

				$member_detail_url = esc_url(
					add_query_arg(
						[
							'page'      => 'rewardswp-members',
							'action'    => 'view_member',
							'member_id' => $advocate->id,
						],
						admin_url( 'admin.php' )
					)
				);

				return sprintf(
					'<div class="group block shrink-0">
						<div class="flex items-center">
							<a href="%s" class="shrink-0">
								<img class="inline-block size-9 rounded-full hover:opacity-80 transition-opacity" src="%s" alt="%s">
							</a>
							<div class="ml-3">
								<a href="%s" class="text-sm font-medium text-[#2271b1] hover:text-[#135e96]">
									%s
								</a>
							</div>
						</div>
					</div>',
					$member_detail_url,
					esc_url_raw(
						get_avatar_url(
							$advocate->email,
							[
								'size' => self::GRAVATAR_SIZE,
							]
						)
					),
					esc_attr( $advocate->get_full_name() ),
					$member_detail_url,
					esc_html( $advocate->get_full_name() )
				);
			case 'referred':
				$customer_name = $this->referrals_service->get_referred_friend_name( $item );

				if ( 'N/A' === $customer_name ) {
					return $customer_name;
				}

				// Try to get member by user_id or email
				$referred_member = null;
				if ( ! empty( $item->referred_user_id ) ) {
					$referred_member = get_member( $item->referred_user_id );
				}

				// If member found, create link to member detail page
				if ( $referred_member && $referred_member->id ) {
					$member_detail_url = esc_url(
						add_query_arg(
							[
								'page'      => 'rewardswp-members',
								'action'    => 'view_member',
								'member_id' => $referred_member->id,
							],
							admin_url( 'admin.php' )
						)
					);

					return sprintf(
						'<div class="group block shrink-0">
							<div class="flex items-center">
								<a href="%s" class="shrink-0">
									<img class="inline-block size-7 md:size-9 rounded-full hover:opacity-80 transition-opacity" src="%s" alt="%s">
								</a>
								<div class="ml-3">
									<a href="%s" class="text-sm font-medium text-[#2271b1] hover:text-[#135e96]">
										%s
									</a>
								</div>
							</div>
						</div>',
						$member_detail_url,
						esc_url_raw(
							get_avatar_url(
								$item->referred_email,
								[
									'size' => self::GRAVATAR_SIZE,
								]
							)
						),
						esc_attr( $customer_name ),
						$member_detail_url,
						esc_html( $customer_name )
					);
				}

				// If not a member, show without link
				return sprintf(
					'<div class="group block shrink-0">
						<div class="flex items-center">
							<img class="inline-block size-7 md:size-9 rounded-full" src="%s" alt="%s">
							<div class="ml-3">
								<p class="text-sm font-medium text-gray-700">%s</p>
							</div>
						</div>
					</div>',
					esc_url_raw(
						get_avatar_url(
							$item->referred_email,
							[
								'size' => self::GRAVATAR_SIZE,
							]
						)
					),
					esc_attr( $customer_name ),
					esc_html( $customer_name )
				);
			case 'order_total':
				$integration = $this->integration_factory->get_integration( $item->source );

				if (
					! is_subclass_of( $integration, IntegrationWithCouponInterface::class ) ||
					empty( $item->order_id )
				) {
					return esc_html__( 'N/A', 'rewardswp' );
				}

				$order_total = $integration->get_order_total_formatted( $item->order_id );

				if ( empty( $order_total ) ) {
					return esc_html__( 'N/A', 'rewardswp' );
				}

				return sprintf(
					'<a href="%s" class="text-[#2271b1] hover:text-[#135e96]">%s</a>',
					$this->referrals_service->get_referred_order_link( $item ),
					wp_kses( $order_total, kses() )
				);
			default:
				return $item->$column_name;
		}
	}

	/**
	 * Get referral counts by status.
	 *
	 * @since 1.0.0
	 *
	 * @return array
	 */
	private function get_status_counts(): array {
		$all_count = $this->referrals_service->count_referrals();
		$counts    = [
			'all' => $all_count,
		];

		foreach ( $this->statuses as $status_key => $status_label ) {
			$counts[ $status_key ] = $this->referrals_service->count_referrals( [ 'status' => strtoupper( $status_key ) ] );
		}

		return $counts;
	}

	/**
	 * Get an associative array ( id => link ) with the list of views available on this table.
	 *
	 * @since 1.0.0
	 *
	 * @return array
	 */
	protected function get_views(): array {
		$counts         = $this->get_status_counts();
		$current_status = sanitize_text_field( filter_input( INPUT_GET, 'status' ) ?? 'all' );

		$views = [
			'all' => $this->get_view_link( 'all', esc_html__( 'All', 'rewardswp' ), $counts['all'], 'all' === $current_status ),
		];

		foreach ( $this->statuses as $status => $label ) {
			$views[ $status ] = $this->get_view_link(
				$status,
				$label,
				$counts[ $status ] ?? 0,
				$current_status === $status
			);
		}

		return $views;
	}

	/**
	 * Helper method to generate view links.
	 *
	 * @param string $status
	 * @param string $label
	 * @param int    $count
	 * @param bool   $current
	 *
	 * @return string
	 */
	private function get_view_link( string $status, string $label, int $count, bool $current = false ): string {
		$query_args = [ 'status' => $status === 'all' ? false : $status ];
		$url        = esc_url( add_query_arg( $query_args ) );
		$class      = $current ? 'current' : 'text-[#2271b1] hover:text-[#135e96]';

		return sprintf(
			'<a href="%s" class="%s">%s <span class="count">(%d)</span></a>',
			$url,
			$class,
			$label,
			$count
		);
	}

	/**
	 * Generates content for a single row of the table.
	 *
	 * Adds a unique ID attribute to each row for debugging/lookup.
	 *
	 * @since 1.1.0
	 *
	 * @param object|array $item The current item. Expects a Referral object.
	 */
	public function single_row( $item ) {
		if ( $item instanceof Referral && isset( $item->id ) ) {
			echo '<tr id="referral-' . esc_attr( $item->id ) . '">';
		} else {
			echo '<tr>';
		}
		$this->single_row_columns( $item );
		echo '</tr>';
	}
}
