<?php
/**
 * Dashboard REST API Controller.
 *
 * @package Ugcify\Admin\API
 */

namespace Ugcify\Admin\API;

use WP_REST_Controller;
use WP_REST_Server;
use WP_REST_Request;
use WP_Error;
use wpdb;

// Exit if accessed directly.
if ( ! defined( 'ABSPATH' ) ) {
	exit;
}

/**
 * Class DashboardAPI

 * phpcs:disable WordPress.DB.DirectDatabaseQuery.DirectQuery,WordPress.DB.DirectDatabaseQuery.NoCaching,WordPress.DB.PreparedSQL.NotPrepared,WordPress.DB.PreparedSQL.InterpolatedNotPrepared,PluginCheck.Security.DirectDB.UnescapedDBParameter,WordPress.DB.SlowDBQuery.slow_db_query_meta_key,WordPress.DB.SlowDBQuery.slow_db_query_meta_value
 */
class DashboardAPI extends WP_REST_Controller {
	/**
	 * Daily counter option key for successful order-complete feedback request emails.
	 *
	 * @var string
	 */
	private const ORDER_COMPLETE_DAILY_COUNT_OPTION = 'ugcify_order_complete_email_daily_counts';

	/**
	 * Namespace.
	 *
	 * @var string
	 */
	protected $namespace = 'ugcify/v1';

	/**
	 * Rest base.
	 *
	 * @var string
	 */
	protected $rest_base = 'dashboard';

	/**
	 * Register routes.
	 *
	 * @return void
	 */
	public function register_routes() {
		register_rest_route(
			$this->namespace,
			'/' . $this->rest_base . '/lightbox-sales',
			array(
				array(
					'methods'             => WP_REST_Server::READABLE,
					'callback'            => array( $this, 'get_lightbox_sales_metrics' ),
					'permission_callback' => array( $this, 'check_permission' ),
					'args'                => array(
						'start_date' => array(
							'type'              => 'string',
							'required'          => false,
							'sanitize_callback' => 'sanitize_text_field',
							'validate_callback' => array( $this, 'validate_date_param' ),
						),
						'end_date'   => array(
							'type'              => 'string',
							'required'          => false,
							'sanitize_callback' => 'sanitize_text_field',
							'validate_callback' => array( $this, 'validate_date_param' ),
						),
					),
				),
			)
		);
	}

	/**
	 * Check permission.
	 *
	 * @return bool|WP_Error
	 */
	public function check_permission() {
		if ( ! current_user_can( 'manage_options' ) ) {
			return new WP_Error(
				'rest_forbidden',
				__( 'Sorry, you are not allowed to access this resource.', 'ugcify' ),
				array( 'status' => 403 )
			);
		}

		return true;
	}

	/**
	 * Get lightbox sales metrics.
	 *
	 * @param WP_REST_Request $request Request object.
	 * @return \WP_REST_Response
	 */
	public function get_lightbox_sales_metrics( $request ) {
		$metrics = array(
			'total_reviews'     => 0,
			'average_rating'    => 0,
			'review_request_sent' => 0,
			'total_orders'      => 0,
			'total_revenue'     => 0,
			'top_products'      => array(),
			'formatted_revenue' => function_exists( 'wc_price' ) ? $this->format_money_plain( 0 ) : '0',
			'currency_symbol'   => function_exists( 'get_woocommerce_currency_symbol' ) ? get_woocommerce_currency_symbol() : '',
			'currency_code'     => function_exists( 'get_woocommerce_currency' ) ? get_woocommerce_currency() : '',
		);

		$date_range = $this->get_date_range_from_request( $request );
		$metrics    = array_merge( $metrics, $this->get_review_metrics( $date_range['start_datetime'], $date_range['end_datetime'] ) );
		$metrics['review_request_sent'] = $this->get_order_complete_request_sent_count( $date_range['start_datetime'], $date_range['end_datetime'] );

		if ( ! function_exists( 'wc_get_orders' ) ) {
			return rest_ensure_response(
				array(
					'success' => true,
					'data'    => $metrics,
				)
			);
		}

		$order_statuses    = array_keys( wc_get_order_statuses() );
		$included_statuses = array_map(
			static function ( $status ) {
				$status = sanitize_key( (string) $status );
				return 0 === strpos( $status, 'wc-' ) ? $status : "wc-{$status}";
			},
			(array) apply_filters( 'ugcify_dashboard_included_statuses', array( 'wc-completed' ) )
		);

		$included_statuses = array_values( array_intersect( $order_statuses, $included_statuses ) );
		if ( empty( $included_statuses ) ) {
			$included_statuses = array( 'wc-completed' );
		}

		$order_ids = wc_get_orders(
			array(
				'return'     => 'ids',
				'limit'      => -1,
				'type'       => 'shop_order',
				'status'     => $included_statuses,
				'meta_key'   => '_ugcify_has_lightbox_sale',
				'meta_value' => 'yes',
			)
		);

		if ( empty( $order_ids ) ) {
			return rest_ensure_response(
				array(
					'success' => true,
					'data'    => $metrics,
				)
			);
		}

		$total_revenue            = 0.0;
		$valid_orders             = 0;
		$product_revenue_map_all  = array();
		foreach ( $order_ids as $order_id ) {
			$order = wc_get_order( $order_id );
			if ( ! $order ) {
				continue;
			}

			// Top Products revenue is all-time UGC-attributed completed sales.
			$this->accumulate_order_product_revenue( $order, $product_revenue_map_all );

			if ( ! $this->is_order_within_date_range( $order, $date_range['start_timestamp'], $date_range['end_timestamp'] ) ) {
				continue;
			}

			$revenue = (float) $order->get_meta( '_ugcify_lightbox_revenue', true );
			if ( $revenue <= 0 ) {
				$summary = $order->get_meta( '_ugcify_lightbox_summary', true );
				$revenue = is_array( $summary ) && isset( $summary['tracked_revenue'] ) ? (float) $summary['tracked_revenue'] : 0.0;
			}
			++$valid_orders;
			$total_revenue += $revenue;
		}

		$total_revenue = (float) wc_format_decimal( $total_revenue, wc_get_price_decimals() );
		$top_products  = $this->get_top_products_metrics( '', '', $product_revenue_map_all );
		$metrics       = array(
			'total_reviews'     => (int) $metrics['total_reviews'],
			'average_rating'    => (float) $metrics['average_rating'],
			'review_request_sent' => (int) $metrics['review_request_sent'],
			'total_orders'      => $valid_orders,
			'total_revenue'     => $total_revenue,
			'top_products'      => $top_products,
			'formatted_revenue' => $this->format_money_plain( $total_revenue ),
			'currency_symbol'   => get_woocommerce_currency_symbol(),
			'currency_code'     => get_woocommerce_currency(),
		);

		return rest_ensure_response(
			array(
				'success' => true,
				'data'    => $metrics,
			)
		);
	}

	/**
	 * Sum successful order-complete request emails within selected date range.
	 *
	 * @param string $start_datetime Start datetime string.
	 * @param string $end_datetime   End datetime string.
	 * @return int
	 */
	private function get_order_complete_request_sent_count( $start_datetime, $end_datetime ) {
		$counts = get_option( self::ORDER_COMPLETE_DAILY_COUNT_OPTION, array() );
		$counts = $this->normalize_daily_counts_option( $counts );

		if ( empty( $counts ) ) {
			return 0;
		}

		$start_date = '';
		$end_date   = '';
		if ( is_string( $start_datetime ) && preg_match( '/^\d{4}-\d{2}-\d{2}/', $start_datetime ) ) {
			$start_date = substr( $start_datetime, 0, 10 );
		}

		if ( is_string( $end_datetime ) && preg_match( '/^\d{4}-\d{2}-\d{2}/', $end_datetime ) ) {
			$end_date = substr( $end_datetime, 0, 10 );
		}

		$total = 0;
		foreach ( $counts as $date_key => $count ) {
			if ( $start_date && $date_key < $start_date ) {
				continue;
			}
			if ( $end_date && $date_key > $end_date ) {
				continue;
			}

			$total += $count;
		}

		return (int) $total;
	}

	/**
	 * Normalize daily counts option into a safe date=>count map.
	 *
	 * @param mixed $value Raw option value.
	 * @return array<string,int>
	 */
	private function normalize_daily_counts_option( $value ) {
		if ( ! is_array( $value ) ) {
			return array();
		}

		$normalized = array();
		foreach ( $value as $date_key => $count ) {
			if ( ! is_string( $date_key ) || ! preg_match( '/^\d{4}-\d{2}-\d{2}$/', $date_key ) ) {
				continue;
			}

			$normalized[ $date_key ] = absint( $count );
		}

		return $normalized;
	}

	/**
	 * Convert WooCommerce HTML price into plain UTF-8 text.
	 *
	 * @param float $amount Amount.
	 * @return string
	 */
	private function format_money_plain( $amount ) {
		$raw = wp_strip_all_tags( wc_price( $amount ) );
		$raw = html_entity_decode( $raw, ENT_QUOTES, get_bloginfo( 'charset' ) );
		$raw = preg_replace( '/\x{00A0}/u', ' ', $raw );

		return trim( (string) $raw );
	}

	/**
	 * Validate YYYY-MM-DD date input.
	 *
	 * @param mixed           $value   Param value.
	 * @param WP_REST_Request $request Request object.
	 * @param string          $param   Param name.
	 * @return bool
	 */
	public function validate_date_param( $value, $request, $param ) {
		unset( $request, $param );
		if ( null === $value || '' === $value ) {
			return true;
		}

		return (bool) preg_match( '/^\d{4}-\d{2}-\d{2}$/', (string) $value );
	}

	/**
	 * Parse dashboard date range params from request.
	 *
	 * @param WP_REST_Request $request Request object.
	 * @return array<string,mixed>
	 */
	private function get_date_range_from_request( WP_REST_Request $request ) {
		$start_date = sanitize_text_field( (string) $request->get_param( 'start_date' ) );
		$end_date   = sanitize_text_field( (string) $request->get_param( 'end_date' ) );

		$start_datetime = '';
		$end_datetime   = '';
		$start_ts       = null;
		$end_ts         = null;

		if ( $start_date && preg_match( '/^\d{4}-\d{2}-\d{2}$/', $start_date ) ) {
			$start_datetime = $start_date . ' 00:00:00';
			$start_ts       = strtotime( $start_datetime );
		}

		if ( $end_date && preg_match( '/^\d{4}-\d{2}-\d{2}$/', $end_date ) ) {
			$end_datetime = $end_date . ' 23:59:59';
			$end_ts       = strtotime( $end_datetime );
		}

		return array(
			'start_datetime' => $start_datetime,
			'end_datetime'   => $end_datetime,
			'start_timestamp' => $start_ts,
			'end_timestamp'   => $end_ts,
		);
	}

	/**
	 * Get Total Review and Average Rating for date range.
	 *
	 * @param string $start_datetime Start datetime.
	 * @param string $end_datetime   End datetime.
	 * @return array<string,mixed>
	 */
	private function get_review_metrics( $start_datetime, $end_datetime ) {
		global $wpdb;
		if ( ! ( $wpdb instanceof wpdb ) ) {
			return array(
				'total_reviews'  => 0,
				'average_rating' => 0,
			);
		}

		$table_name = $wpdb->prefix . 'ugcify_reviews';
		$conditions = array(
			"status = 'approved'",
			'rating IS NOT NULL',
			'rating >= 1',
			"type NOT IN ('instagram', 'youtube', 'tiktok')",
		);
		$values     = array();

		if ( $start_datetime ) {
			$conditions[] = 'created_at >= %s';
			$values[]     = $start_datetime;
		}

		if ( $end_datetime ) {
			$conditions[] = 'created_at <= %s';
			$values[]     = $end_datetime;
		}

		$where_sql = 'WHERE ' . implode( ' AND ', $conditions );
		// phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared,WordPress.DB.PreparedSQL.InterpolatedNotPrepared -- Table name is a trusted internal constant; values use prepare() placeholders.
		$sql       = "SELECT COUNT(*) AS total_reviews, AVG(rating) AS average_rating FROM {$table_name} {$where_sql}";
		if ( ! empty( $values ) ) {
			$sql = $wpdb->prepare( $sql, $values ); // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared
		}

		$result = $wpdb->get_row( $sql, ARRAY_A ); // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery,WordPress.DB.DirectDatabaseQuery.NoCaching,WordPress.DB.PreparedSQL.NotPrepared
		if ( ! is_array( $result ) ) {
			return array(
				'total_reviews'  => 0,
				'average_rating' => 0,
			);
		}

		return array(
			'total_reviews'  => (int) $result['total_reviews'],
			'average_rating' => isset( $result['average_rating'] ) ? round( (float) $result['average_rating'], 1 ) : 0,
		);
	}

	/**
	 * Check if order creation date is within selected range.
	 *
	 * @param \WC_Order $order    Order object.
	 * @param int|null  $start_ts Start timestamp.
	 * @param int|null  $end_ts   End timestamp.
	 * @return bool
	 */
	private function is_order_within_date_range( $order, $start_ts, $end_ts ) {
		if ( null === $start_ts && null === $end_ts ) {
			return true;
		}

		$created = $order->get_date_created();
		if ( ! $created ) {
			return false;
		}

		$order_ts = (int) $created->getTimestamp();
		if ( null !== $start_ts && $order_ts < $start_ts ) {
			return false;
		}

		if ( null !== $end_ts && $order_ts > $end_ts ) {
			return false;
		}

		return true;
	}

	/**
	 * Accumulate per-product UGC tracked revenue for one order.
	 *
	 * @param \WC_Order $order Order object.
	 * @param array     $product_revenue_map Revenue map passed by reference.
	 * @return void
	 */
	private function accumulate_order_product_revenue( $order, &$product_revenue_map ) {
		foreach ( $order->get_items( 'line_item' ) as $item ) {
			$product_id = absint( $item->get_product_id() );
			if ( $product_id <= 0 ) {
				continue;
			}

			$tracking = $item->get_meta( '_ugcify_lightbox_tracking', true );
			if ( ! is_array( $tracking ) ) {
				continue;
			}

			$line_quantity    = max( 1, absint( $item->get_quantity() ) );
			$tracked_quantity = isset( $tracking['tracked_quantity'] ) ? absint( $tracking['tracked_quantity'] ) : 0;
			if ( $tracked_quantity <= 0 ) {
				$tracked_quantity = absint( $item->get_meta( '_ugcify_tracked_quantity', true ) );
			}
			$tracked_quantity = min( $line_quantity, max( 0, $tracked_quantity ) );
			if ( $tracked_quantity <= 0 ) {
				continue;
			}

			$line_total    = (float) $item->get_total();
			$tracked_ratio = min( 1, max( 0, $tracked_quantity / $line_quantity ) );
			$tracked_value = $line_total * $tracked_ratio;

			if ( ! isset( $product_revenue_map[ $product_id ] ) ) {
				$product_revenue_map[ $product_id ] = 0.0;
			}

			$product_revenue_map[ $product_id ] += $tracked_value;
		}
	}

	/**
	 * Build Top Products payload sorted by avg rating desc then revenue desc.
	 *
	 * @param string $start_datetime Start datetime.
	 * @param string $end_datetime End datetime.
	 * @param array  $product_revenue_map Per-product revenue map.
	 * @return array
	 */
	private function get_top_products_metrics( $start_datetime, $end_datetime, $product_revenue_map ) {
		global $wpdb;
		if ( ! ( $wpdb instanceof wpdb ) ) {
			return array();
		}

		$table_name = $wpdb->prefix . 'ugcify_reviews';
		$conditions = array(
			"status = 'approved'",
			'product_id > 0',
			'rating IS NOT NULL',
			'rating >= 1',
			"type NOT IN ('instagram', 'youtube', 'tiktok')",
		);
		$values = array();

		if ( $start_datetime ) {
			$conditions[] = 'created_at >= %s';
			$values[]     = $start_datetime;
		}

		if ( $end_datetime ) {
			$conditions[] = 'created_at <= %s';
			$values[]     = $end_datetime;
		}

		$where_sql = 'WHERE ' . implode( ' AND ', $conditions );
		// phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared,WordPress.DB.PreparedSQL.InterpolatedNotPrepared -- Table name is a trusted internal constant; values use prepare() placeholders.
		$sql       = "SELECT product_id, COUNT(*) AS total_reviews, AVG(rating) AS average_rating
			FROM {$table_name}
			{$where_sql}
			GROUP BY product_id";

		if ( ! empty( $values ) ) {
			$sql = $wpdb->prepare( $sql, $values ); // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared
		}

		$rows = $wpdb->get_results( $sql, ARRAY_A ); // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery,WordPress.DB.DirectDatabaseQuery.NoCaching,WordPress.DB.PreparedSQL.NotPrepared
		if ( ! is_array( $rows ) || empty( $rows ) ) {
			return array();
		}

		$products = array();
		foreach ( $rows as $row ) {
			$product_id = absint( $row['product_id'] );
			if ( $product_id <= 0 ) {
				continue;
			}

			$product = function_exists( 'wc_get_product' ) ? wc_get_product( $product_id ) : null;
			/* translators: %d: product ID number */
			$product_name = $product ? $product->get_name() : sprintf( __( 'Product #%d', 'ugcify' ), $product_id );
			$revenue = isset( $product_revenue_map[ $product_id ] ) ? (float) $product_revenue_map[ $product_id ] : 0.0;
			$revenue = (float) wc_format_decimal( $revenue, wc_get_price_decimals() );

			$products[] = array(
				'product_id'        => $product_id,
				'product_name'      => $product_name,
				'product_url'       => $product ? $product->get_permalink() : get_permalink( $product_id ),
				'total_reviews'     => (int) $row['total_reviews'],
				'average_rating'    => round( (float) $row['average_rating'], 1 ),
				'total_revenue'     => $revenue,
				'formatted_revenue' => $this->format_money_plain( $revenue ),
			);
		}

		usort(
			$products,
			static function ( $a, $b ) {
				if ( $a['average_rating'] === $b['average_rating'] ) {
					if ( $a['total_revenue'] === $b['total_revenue'] ) {
						return 0;
					}
					return ( $a['total_revenue'] > $b['total_revenue'] ) ? -1 : 1;
				}

				return ( $a['average_rating'] > $b['average_rating'] ) ? -1 : 1;
			}
		);

		return array_slice( $products, 0, 6 );
	}
}
