<?php
/**
 * Class Noesia Cs Commerce View Service.
 *
 * @package Noesia_Commerce_Suite
 */

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

/**
 * Read-only WooCommerce operational views for the Noesia admin shell.
 */
class Noesia_CS_Commerce_View_Service {
	/**
	 * Runtime dependency or state value.
	 *
	 * @var mixed
	 */
	private $order_repository;
	/**
	 * Runtime dependency or state value.
	 *
	 * @var mixed
	 */
	private $passport_service;

	/**
	 * Handles the related plugin operation.
	 *
	 * @param mixed $order_repository Order repository.
	 * @param mixed $passport_service Passport service.
	 */
	public function __construct( Noesia_CS_Order_Repository $order_repository = null, Noesia_CS_Passport_Service $passport_service = null ) {
		$this->order_repository = $order_repository ? $order_repository : new Noesia_CS_Order_Repository();
		$this->passport_service = $passport_service;
	}

	/**
	 * Handles the related plugin operation.
	 *
	 * @param mixed $args Args.
	 */
	public function get_orders_view( $args = array() ) {
		$defaults = array(
			'page'    => 1,
			'limit'   => 20,
			'status'  => 'all',
		);
		$args    = wp_parse_args( is_array( $args ) ? $args : array(), $defaults );
		$page    = max( 1, absint( $args['page'] ) );
		$limit   = max( 5, min( 50, absint( $args['limit'] ) ) );
		$status  = sanitize_key( $args['status'] );

		if ( ! $this->order_repository->is_available() ) {
			return array(
				'available'       => false,
				'orders'          => array(),
				'total'           => 0,
				'max_num_pages'   => 0,
				'current_page'    => $page,
				'current_status'  => 'all',
			);
		}

		$query_args = array(
			'limit'     => $limit,
			'paged'     => $page,
			'paginate'  => true,
			'orderby'   => 'date',
			'order'     => 'DESC',
			'return'    => 'objects',
		);

		if ( 'all' !== $status && $status ) {
			$query_args['status'] = array( 'wc-' . $status );
		}

		$result  = wc_get_orders( $query_args );
		$orders  = is_object( $result ) && isset( $result->orders ) ? $result->orders : ( is_array( $result ) ? $result : array() );
		$items   = array();

		foreach ( $orders as $order ) {
			if ( ! is_a( $order, 'WC_Order' ) ) {
				continue;
			}
			$items[] = $this->format_order_row( $order );
		}

		return array(
			'available'       => true,
			'orders'          => $items,
			'total'           => is_object( $result ) && isset( $result->total ) ? absint( $result->total ) : count( $items ),
			'max_num_pages'   => is_object( $result ) && isset( $result->max_num_pages ) ? absint( $result->max_num_pages ) : 1,
			'current_page'    => $page,
			'current_status'  => $status ? $status : 'all',
		);
	}

	/**
	 * Handles the related plugin operation.
	 *
	 * @param mixed $args Args.
	 */
	public function get_customers_view( $args = array() ) {
		global $wpdb;

		$defaults = array(
			'page'   => 1,
			'limit'  => 20,
		);
		$args   = wp_parse_args( is_array( $args ) ? $args : array(), $defaults );
		$page   = max( 1, absint( $args['page'] ) );
		$limit  = max( 5, min( 50, absint( $args['limit'] ) ) );

		if ( ! isset( $wpdb ) || ! $this->order_repository->is_available() ) {
			return array(
				'available'      => false,
				'customers'      => array(),
				'total'          => 0,
				'max_num_pages'  => 0,
				'current_page'   => $page,
			);
		}

		$order_stats  = $wpdb->prefix . 'wc_order_stats';
		$lookup       = $wpdb->prefix . 'wc_customer_lookup';
		if ( ! $this->table_exists( $order_stats ) || ! $this->table_exists( $lookup ) ) {
			return array(
				'available'      => false,
				'customers'      => array(),
				'total'          => 0,
				'max_num_pages'  => 0,
				'current_page'   => $page,
				'note'           => __( 'WooCommerce customer lookup tables are not available yet.', 'noesia-commerce-suite' ),
			);
		}

		$valid_statuses  = array( 'wc-completed', 'wc-processing', 'wc-on-hold' );
		$offset          = ( $page - 1 ) * $limit;

		$total = absint(
			// phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching -- Read-only customer count lookup using WooCommerce reporting tables.
			$wpdb->get_var(
				$wpdb->prepare(
					'SELECT COUNT(*) FROM (
						SELECT customer_id
						FROM %i
						WHERE customer_id > 0 AND status IN (%s,%s,%s)
						GROUP BY customer_id
					) grouped_customers',
					$order_stats,
					$valid_statuses[0],
					$valid_statuses[1],
					$valid_statuses[2]
				)
			)
		);

		// phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching -- Read-only customer lookup using WooCommerce reporting tables.
		$rows = $wpdb->get_results(
			$wpdb->prepare(
				'SELECT stats.customer_id, stats.orders_count, stats.total_spend, stats.last_order_date, customers.user_id, customers.first_name, customers.last_name, customers.email, customers.city, customers.country
				FROM (
					SELECT customer_id, COUNT(*) AS orders_count, SUM(net_total) AS total_spend, MAX(date_created) AS last_order_date
					FROM %i
					WHERE customer_id > 0 AND status IN (%s,%s,%s)
					GROUP BY customer_id
				) stats
				LEFT JOIN %i customers ON customers.customer_id = stats.customer_id
				ORDER BY stats.last_order_date DESC
				LIMIT %d OFFSET %d',
				$order_stats,
				$valid_statuses[0],
				$valid_statuses[1],
				$valid_statuses[2],
				$lookup,
				$limit,
				$offset
			),
			ARRAY_A
		);
		$items = array();
		if ( is_array( $rows ) ) {
			foreach ( $rows as $row ) {
				$items[] = $this->format_customer_row( $row );
			}
		}

		return array(
			'available'      => true,
			'customers'      => $items,
			'total'          => $total,
			'max_num_pages'  => $limit ? (int) ceil( $total / $limit ) : 1,
			'current_page'   => $page,
		);
	}

	/**
	 * Handles the related plugin operation.
	 *
	 * @param mixed $order Order.
	 */
	private function format_order_row( $order ) {
		$order_id           = absint( $order->get_id() );
		$created            = $order->get_date_created();
		$created_timestamp  = $created ? $created->getTimestamp() : 0;
		$items_count        = 0;
		foreach ( $order->get_items() as $item ) {
			$items_count += absint( $item->get_quantity() );
		}

		$has_token = $this->passport_service && method_exists( $this->passport_service, 'order_has_active_token' ) ? $this->passport_service->order_has_active_token( $order ) : false;

		return array(
			'order_id'        => $order_id,
			'order_number'    => sanitize_text_field( $order->get_order_number() ),
			'customer_label'  => $this->get_order_customer_label( $order ),
			'total'           => (float) $order->get_total(),
			'status'          => sanitize_key( $order->get_status() ),
			'status_label'    => function_exists( 'wc_get_order_status_name' ) ? wc_get_order_status_name( $order->get_status() ) : sanitize_text_field( $order->get_status() ),
			'time_ago'        => $created_timestamp ? sprintf( /* translators: %s: dynamic value. */ __( '%s ago', 'noesia-commerce-suite' ), human_time_diff( $created_timestamp, time() ) ) : __( 'Recently', 'noesia-commerce-suite' ),
			'created_label'   => $created ? $created->date_i18n( get_option( 'date_format' ) . ' ' . get_option( 'time_format' ) ) : '',
			'thumbnail'       => $this->get_order_first_product_thumbnail( $order ),
			'items_count'     => $items_count,
			'has_passport'    => $has_token,
			'url'             => method_exists( $order, 'get_edit_order_url' ) ? esc_url_raw( $order->get_edit_order_url() ) : '',
		);
	}

	/**
	 * Handles the related plugin operation.
	 *
	 * @param mixed $row Row.
	 */
	private function format_customer_row( $row ) {
		$customer_id  = absint( $row['customer_id'] ?? 0 );
		$user_id      = absint( $row['user_id'] ?? 0 );
		$first_name   = sanitize_text_field( $row['first_name'] ?? '' );
		$last_name    = sanitize_text_field( $row['last_name'] ?? '' );
		$email        = sanitize_email( $row['email'] ?? '' );
		$name         = trim( $first_name . ' ' . $last_name );

		if ( ! $name && $user_id ) {
			$user  = get_userdata( $user_id );
			$name  = $user ? sanitize_text_field( $user->display_name ) : '';
		}
		if ( ! $name ) {
			$name = $email ? sprintf( /* translators: %s: dynamic value. */ __( 'Customer %s', 'noesia-commerce-suite' ), strtoupper( substr( md5( strtolower( $email ) ), 0, 6 ) ) ) : sprintf( /* translators: %d: numeric value. */ __( 'Customer #%d', 'noesia-commerce-suite' ), $customer_id );
		}

		$location_parts = array_filter(
			array(
				sanitize_text_field( $row['city'] ?? '' ),
				sanitize_text_field( $row['country'] ?? '' ),
			)
		);

		$url = '';
		if ( $user_id ) {
			$url = admin_url( 'user-edit.php?user_id=' . $user_id );
		} elseif ( $customer_id ) {
			$url = add_query_arg(
				array(
					'page'       => 'wc-admin',
					'path'       => '/customers',
					'filter'     => 'single_customer',
					'customers'  => $customer_id,
				),
				admin_url( 'admin.php' )
			);
		}

		return array(
			'customer_id'   => $customer_id,
			'user_id'       => $user_id,
			'label'         => $name,
			'orders_count'  => absint( $row['orders_count'] ?? 0 ),
			'total_spend'   => (float) ( $row['total_spend'] ?? 0 ),
			'last_order'    => sanitize_text_field( $row['last_order_date'] ?? '' ),
			'location'      => $location_parts ? implode( ', ', $location_parts ) : __( 'No public location summary', 'noesia-commerce-suite' ),
			'is_repeat'     => absint( $row['orders_count'] ?? 0 ) > 1,
			'url'           => esc_url_raw( $url ),
		);
	}

	/**
	 * Handles the related plugin operation.
	 *
	 * @param mixed $order Order.
	 */
	private function get_order_customer_label( $order ) {
		$first  = sanitize_text_field( $order->get_billing_first_name() );
		$last   = sanitize_text_field( $order->get_billing_last_name() );
		$name   = trim( $first . ' ' . $last );
		if ( $name ) {
			return $name;
		}
		$customer_id = absint( $order->get_customer_id() );
		return $customer_id ? sprintf( /* translators: %d: numeric value. */ __( 'Customer #%d', 'noesia-commerce-suite' ), $customer_id ) : __( 'Guest customer', 'noesia-commerce-suite' );
	}

	/**
	 * Handles the related plugin operation.
	 *
	 * @param mixed $order Order.
	 */
	private function get_order_first_product_thumbnail( $order ) {
		foreach ( $order->get_items() as $item ) {
			$product = method_exists( $item, 'get_product' ) ? $item->get_product() : null;
			if ( ! $product || ! method_exists( $product, 'get_image_id' ) ) {
				continue;
			}
			$image_id = absint( $product->get_image_id() );
			if ( $image_id ) {
				$url = wp_get_attachment_image_url( $image_id, 'thumbnail' );
				if ( $url ) {
					return esc_url_raw( $url );
				}
			}
		}
		return '';
	}

	/**
	 * Handles the related plugin operation.
	 *
	 * @param mixed $table Table.
	 */
	private function table_exists( $table ) {
		global $wpdb;
		if ( ! isset( $wpdb ) || ! $table ) {
			return false;
		}
		$found = $wpdb->get_var( $wpdb->prepare( 'SHOW TABLES LIKE %s', $table ) ); // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching
		return $found === $table;
	}
}
