<?php
/**
 * Flow
 *
 * @package cartflows
 */

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

use Automattic\WooCommerce\Utilities\OrderUtil;
/**
 * Analytics reports class.
 */
class Cartflows_Pro_Analytics_Reports {

	/**
	 * Member Variable
	 *
	 * @var object instance
	 */
	private static $instance;

	/**
	 * Flow orders
	 *
	 * @var array flow_orders
	 */
	private static $flow_orders = array();

	/**
	 * Flow gross sell
	 *
	 * @var int flow_gross
	 */
	private static $flow_gross = 0;

	/**
	 * Flow visits
	 *
	 * @var array flow_visits
	 */
	private static $flow_visits = array();

	/**
	 * Steps data
	 *
	 * @var array step_data
	 */
	private static $step_data = array();

	/**
	 * Earnings for flow
	 *
	 * @var array flow_earnings
	 */
	private static $flow_earnings = array();

	/**
	 * Report interval
	 *
	 * @var int report_interval
	 */
	private static $report_interval = 30;

	/**
	 *  Initiator
	 */
	public static function get_instance() {
		if ( ! isset( self::$instance ) ) {
			self::$instance = new self();
		}
		return self::$instance;
	}

	/**
	 * Constructor function that initializes required actions and hooks
	 */
	public function __construct() {
		add_filter( 'cartflows_home_page_analytics', array( $this, 'get_home_page_analytics_data' ), 10, 6 );
	}

	/**
	 * Get home page analytics.
	 * Orchestrates analytics data retrieval based on screen type.
	 *
	 * @param array  $analytics_data analytics.
	 * @param string $start_date start date.
	 * @param string $end_date end date.
	 * @param string $dashboard_flow_id flow ID (empty for all flows).
	 * @param string $screen_type screen type ('funnels', 'conversions', or 'optins').
	 * @param string $comparison_range_type comparison range type.
	 * @return array Complete analytics data for the requested screen.
	 */
	public function get_home_page_analytics_data( $analytics_data, $start_date, $end_date, $dashboard_flow_id, $screen_type, $comparison_range_type = '' ) {
		// Orchestrate analytics based on screen type.
		switch ( $screen_type ) {
			case 'funnels':
				return wcf_pro_analytics()->funnels->get_analytics_data( $analytics_data, $start_date, $end_date, $dashboard_flow_id, $comparison_range_type );

			case 'conversions':
				return wcf_pro_analytics()->conversions->get_analytics_data( $analytics_data, $start_date, $end_date, $dashboard_flow_id, $comparison_range_type );

			case 'optins':
				return wcf_pro_analytics()->optin->get_analytics_data( $analytics_data, $start_date, $end_date, $dashboard_flow_id, $comparison_range_type );

			default:
				// Fallback to funnels if screen type is not recognized.
				return wcf_pro_analytics()->funnels->get_analytics_data( $analytics_data, $start_date, $end_date, $dashboard_flow_id, $comparison_range_type );
		}
	}

	/**
	 * Get earnings for a flow (delegates to database helper).
	 * Kept for backward compatibility with flow-analytics.php.
	 *
	 * @param string $flow_id Flow ID.
	 * @param string $start_date Start date.
	 * @param string $end_date End date.
	 * @return array Earnings data.
	 */
	public function get_earnings( $flow_id, $start_date, $end_date ) {
		$earning_data = wcf_pro_analytics()->database->get_earnings( $flow_id, $start_date, $end_date );

		// Add revenue_per_unique_visitors if not already present.
		if ( ! isset( $earning_data['revenue_per_unique_visits'] ) ) {
			$rpuv_data                                 = wcf_pro_analytics()->calculations->calculate_revenue_per_unique_visitor( $start_date, $end_date, $flow_id );
			$earning_data['revenue_per_unique_visits'] = wcf_pro_analytics()->format_price( $rpuv_data['revenue_per_unique_visitor'] );
		}

		return $earning_data;
	}

	/**
	 * Fetch visits for a flow (delegates to database helper).
	 * Kept for backward compatibility with flow-analytics.php.
	 *
	 * @param int    $flow_id Flow ID.
	 * @param string $start_date Start date.
	 * @param string $end_date End date.
	 * @param string $screen_type Whether from flow analytics.
	 * @return array Visits data.
	 */
	public function fetch_visits( $flow_id, $start_date, $end_date, $screen_type = '' ) {
		return wcf_pro_analytics()->database->fetch_visits( $flow_id, $start_date, $end_date, $screen_type );
	}

	/**
	 * Build step analytics data structure (delegates to calculations helper).
	 * Maps visit data and earnings to flow steps.
	 *
	 * @param int   $flow_id Flow ID.
	 * @param array $visits Visits data.
	 * @param array $earning Earning data.
	 * @return array Steps array with analytics data attached.
	 */
	public function build_steps_with_analytics( $flow_id, $visits, $earning ) {
		return wcf_pro_analytics()->calculations->build_steps_with_analytics( $flow_id, $visits, $earning );
	}

	/**
	 * Get revenue of flow.
	 *
	 * @param int $flow_id flow id.
	 * @return int
	 */
	public function get_gross_sale_by_flow( $flow_id ) {

		//phpcs:disable WordPress.DB.SlowDBQuery
		// Fetch primary orders: Checkout, Order Bumps.
		$args = array(
			'status'       => array( 'completed', 'processing', 'cancelled' ), // Accepts a string: one of 'pending', 'processing', 'on-hold', 'completed', 'refunded, 'failed', 'cancelled', or a custom order status.
			'meta_key'     => '_wcf_flow_id', // Postmeta key field.
			'meta_value'   => $flow_id, // Postmeta value field.
			'meta_compare' => '=', // Possible values are '=', '!=', '>', '>=', '<', '<=', 'LIKE', 'NOT LIKE', 'IN', 'NOT IN', 'BETWEEN', 'NOT BETWEEN', 'EXISTS' (only in WP >= 3.5), and 'NOT EXISTS' (also only in WP >= 3.5). Values 'REGEXP', 'NOT REGEXP' and 'RLIKE' were added in WordPress 3.7. Default value is '='.
			'return'       => 'ids', // Accepts a string: 'ids' or 'objects'. Default: 'objects'.
		);

		/**
		 * Parent order IDs.
		 *
		 * @var int[] $parent_orders
		 */
		$parent_orders = wc_get_orders( $args );

		// Fetch separate/child orders.
		$args = array(
			'status'       => array( 'completed', 'processing', 'cancelled' ), // Accepts a string: one of 'pending', 'processing', 'on-hold', 'completed', 'refunded, 'failed', 'cancelled', or a custom order status.
			'meta_key'     => '_cartflows_parent_flow_id', // Postmeta key field.
			'meta_value'   => $flow_id, // Postmeta value field.
			'meta_compare' => '=', // Possible values are '=', '!=', '>', '>=', '<', '<=', 'LIKE', 'NOT LIKE', 'IN', 'NOT IN', 'BETWEEN', 'NOT BETWEEN', 'EXISTS' (only in WP >= 3.5), and 'NOT EXISTS' (also only in WP >= 3.5). Values 'REGEXP', 'NOT REGEXP' and 'RLIKE' were added in WordPress 3.7. Default value is '='.
			'return'       => 'ids', // Accepts a string: 'ids' or 'objects'. Default: 'objects'.
		);

		//phpcs:enable WordPress.DB.SlowDBQuery

		/**
		 * Child order IDs.
		 *
		 * @var int[] $child_orders
		 */
		$child_orders = wc_get_orders( $args );

		/**
		 * Order IDs returned from both queries.
		 *
		 * @var int[] $orders
		 */
		$orders = array_merge( $parent_orders, $child_orders );

		$gross_sale = 0;

		if ( ! empty( $orders ) ) {

			// Bulk fetch all WC_Order objects at once instead of calling wc_get_order() in loop.
			$order_objects      = array();
				$fetched_orders = wc_get_orders(
					array(
						'include' => $orders,
						'limit'   => -1,
						'return'  => 'objects',
					)
				);

				// Create ID => object map for O(1) lookup.
			if ( is_array( $fetched_orders ) ) {
				foreach ( $fetched_orders as $order_obj ) {
					$order_objects[ $order_obj->get_id() ] = $order_obj;
				}
			}
		}

		foreach ( $orders as $order_id ) {
			// Use pre-fetched order object instead of calling wc_get_order().
			if ( ! isset( $order_objects[ $order_id ] ) ) {
				continue;
			}

			$order   = $order_objects[ $order_id ];
			$user_id = $order->get_user_id();

			// skip the orders which are placed by the user whose user role is Administrator.
			if ( $user_id && user_can( $user_id, 'cartflows_manage_flows_steps' ) ) {
				continue;
			}

			$order_total = $order->get_total();
			if ( ! $order->has_status( 'cancelled' ) ) {
				$gross_sale += (float) $order_total;
			}
		}

		return $gross_sale;
	}

		/**
		 * Get revenue of flow.
		 *
		 * @param int $flow_id flow id.
		 * @return int
		 */
	public function get_conversion_by_flow( $flow_id ) {

		//phpcs:disable WordPress.DB.SlowDBQuery
		$args = array(
			'status'       => array( 'completed', 'processing', 'cancelled' ), // Accepts a string: one of 'pending', 'processing', 'on-hold', 'completed', 'refunded, 'failed', 'cancelled', or a custom order status.
			'meta_key'     => '_wcf_flow_id', // Postmeta key field.
			'meta_value'   => $flow_id, // Postmeta value field.
			'meta_compare' => '=', // Possible values are '=', '!=', '>', '>=', '<', '<=', 'LIKE', 'NOT LIKE', 'IN', 'NOT IN', 'BETWEEN', 'NOT BETWEEN', 'EXISTS' (only in WP >= 3.5), and 'NOT EXISTS' (also only in WP >= 3.5). Values 'REGEXP', 'NOT REGEXP' and 'RLIKE' were added in WordPress 3.7. Default value is '='.
			'return'       => 'ids', // Accepts a string: 'ids' or 'objects'. Default: 'objects'.
		);

		/**
		 * Parent order IDs.
		 *
		 * @var int[] $parent_orders
		 */
		$parent_orders = wc_get_orders( $args );

		$args = array(
			'status'       => array( 'completed', 'processing', 'cancelled' ), // Accepts a string: one of 'pending', 'processing', 'on-hold', 'completed', 'refunded, 'failed', 'cancelled', or a custom order status.
			'meta_key'     => '_cartflows_parent_flow_id', // Postmeta key field.
			'meta_value'   => $flow_id, // Postmeta value field.
			'meta_compare' => '=', // Possible values are '=', '!=', '>', '>=', '<', '<=', 'LIKE', 'NOT LIKE', 'IN', 'NOT IN', 'BETWEEN', 'NOT BETWEEN', 'EXISTS' (only in WP >= 3.5), and 'NOT EXISTS' (also only in WP >= 3.5). Values 'REGEXP', 'NOT REGEXP' and 'RLIKE' were added in WordPress 3.7. Default value is '='.
			'return'       => 'ids', // Accepts a string: 'ids' or 'objects'. Default: 'objects'.
		);

		//phpcs:enable WordPress.DB.SlowDBQuery

		/**
		 * Child order IDs.
		 *
		 * @var int[] $child_orders
		 */
		$child_orders = wc_get_orders( $args );

		/**
		 * Order IDs returned from both queries.
		 *
		 * @var int[] $orders
		 */
		$orders = array_merge( $parent_orders, $child_orders );

		$gross_sale = 0;

		if ( ! empty( $orders ) ) {

			// Bulk fetch all WC_Order objects at once instead of calling wc_get_order() in loop.
			$order_objects      = array();
				$fetched_orders = wc_get_orders(
					array(
						'include' => $orders,
						'limit'   => -1,
						'return'  => 'objects',
					)
				);

				// Create ID => object map for O(1) lookup.
			if ( is_array( $fetched_orders ) ) {
				foreach ( $fetched_orders as $order_obj ) {
					$order_objects[ $order_obj->get_id() ] = $order_obj;
				}
			}
		}

		foreach ( $orders as $order_id ) {
			// Use pre-fetched order object instead of calling wc_get_order().
			if ( ! isset( $order_objects[ $order_id ] ) ) {
				continue;
			}

			$order   = $order_objects[ $order_id ];
			$user_id = $order->get_user_id();

			// skip the orders which are placed by the user whose user role is Administrator.
			if ( $user_id && user_can( $user_id, 'cartflows_manage_flows_steps' ) ) {
				continue;
			}

			$order_total = $order->get_total();
			if ( ! $order->has_status( 'cancelled' ) ) {
				$gross_sale += (float) $order_total;
			}
		}

		return $gross_sale;
	}
}

Cartflows_Pro_Analytics_Reports::get_instance();
