<?php

namespace WC_Affiliate\Controllers\Front;

defined( 'ABSPATH' ) || exit;

// use EasyCommerce\Models\Order_Notes;
use WC_Affiliate\Models\User;
use WC_Affiliate\Models\Visit;
use WC_Order;
use WP_User;

/**
 * Front-end Controller for WC Affiliate Plugin.
 *
 * Handles all front-end functionality including visit tracking, commission processing,
 * affiliate token management, and WooCommerce/EasyCommerce integration.
 *
 * @since 1.0.0
 */
class Init {

	/**
	 * Controller constructor
	 *
	 * Initializes the frontend controller and registers necessary hooks
	 */
	public function __construct() {
		$this->register_hooks();
	}

	/**
	 * Register hooks for front controller
	 *
	 * Registers all necessary hooks for frontend functionality including visit tracking,
	 * commission processing, and WooCommerce/EasyCommerce integrations
	 *
	 * @return void
	 */
	protected function register_hooks(): void {
		add_action( 'wp_footer', array( $this, 'load_legacy_loader_html' ) );

		add_action( 'init', array( $this, 'verify_email' ) );
		add_action( 'wp', array( $this, 'set_token' ) );

		// add_action( 'wp', array( $this, 'track_visit' ) );
		// add_action( 'wp', array( $this, 'apply_discount' ) );

		add_action( 'woocommerce_thankyou', array( $this, 'add_wc_credit' ) );
		add_action( 'easycommerce_after_order', array( $this, 'add_ec_credit' ) );
	}

	/**
	 * Load legacy loader HTML
	 *
	 * Renders legacy loader HTML for backward compatibility
	 *
	 * @return void
	 */
	public function load_legacy_loader_html(): void {
		wca_get_template( 'legacy-loader', 'views/front', array(), false );
	}

	/**
	 * Set affiliate token from URL parameter
	 *
	 * Processes affiliate referral tokens from URL parameters and sets tracking cookies
	 *
	 * @return void
	 */
	public function set_token(): void {
		/**
		 * Action hook fired before token setting.
		 */
		do_action( 'wc_affiliate_set_token_before' );

		if ( is_admin() ) {
			return;
		}

		$ref_key = wca_get_ref_key();
		if ( ! isset( $_GET[ $ref_key ] ) ) { // phpcs:ignore WordPress.Security
			return;
		}

		$token = sanitize_text_field( $_GET[ $ref_key ] ); // phpcs:ignore WordPress.Security
		if ( empty( $token ) ) {
			return;
		}

		$affiliate_user = wca_get_affiliate_user_by_token( $token );
		if ( ! $affiliate_user instanceof WP_User ) {
			return;
		}

		// Check if affiliate is active.
		if ( 'active' !== get_user_meta( $affiliate_user->ID, '_wc_affiliate_status', true ) ) {
			return;
		}

		// Verify self referral.
		if ( wca_allow_self_referral() && get_current_user_id() === $affiliate_user->ID ) {
			return;
		}

		if ( apply_filters( 'wc_affiliate_set_token_disabled', false, $token, $affiliate_user->ID ) ) {
			return;
		}

		// Set cookies.
		$cookie_expiry = wca_get_cookie_expiry();
		$cookie_name   = wca_get_cookie_name();

		if ( ! isset( $_COOKIE[ $cookie_name ] ) || wca_allow_overwrite() ) {
			$_COOKIE[ $cookie_name ] = $token;
			setcookie( $cookie_name, $token, time() + $cookie_expiry, '/' );

			if ( wca_log_enabled() ) {
				$referer_uri = isset( $_SERVER['HTTP_REFERER'] ) ? esc_url_raw( wp_unslash( $_SERVER['HTTP_REFERER'] ) ) : '';
				$current_uri = wca_get_current_uri();
				$visit_model = new Visit();
				$visit_data  = $visit_model->track(
					$affiliate_user->ID,
					$current_uri,
					! empty( $referer_uri ) ? $referer_uri : '',
					isset( $_GET['campaign'] ) ? sanitize_text_field( wp_unslash( $_GET['campaign'] ) ) : '' // phpcs:ignore WordPress.Security
				);

				if ( ! $visit_data instanceof Visit ) {
					return;
				}

				$visit_cookie_name = wca_get_visit_cookie_name();
				$cookie_expiry     = wca_get_cookie_expiry();

				setcookie( $visit_cookie_name, $visit_data->get_id(), time() + $cookie_expiry, '/' );

				$_COOKIE[ $visit_cookie_name ] = $visit_data->get_id();
			}
		}

		/**
		 * Action hook fired after token setting.
		 *
		 * @param int $user_id User ID.
		 * @param string $token Affiliate token.
		 */
		do_action( 'wc_affiliate_set_token_after', $affiliate_user->ID, $token );
	}

	/**
	 * Track affiliate visits
	 */
	// public function track_visit() {
	// **
	// * Action hook fired before visit tracking.
	// */
	// do_action( 'wc_affiliate_track_visit_before' );
	//
	// $user = wca_validate_referral_token();
	// if ( ! $user instanceof WP_User ) {
	// return;
	// }
	//
	// $cookie_name = wca_get_cookie_name();
	// if ( ! isset( $_COOKIE[ $cookie_name ] ) ) {
	// return;
	// }
	//
	// $referer_uri = isset( $_SERVER['HTTP_REFERER'] ) ? esc_url_raw( wp_unslash( $_SERVER['HTTP_REFERER'] ) ) : '';
	// $current_uri = wca_get_current_uri();
	// $visit_model = new Visit();
	// $visit_data  = $visit_model->track(
	// $user->ID,
	// $current_uri,
	// ! empty( $referer_uri ) ? $referer_uri : '',
	// isset( $_GET['campaign'] ) ? sanitize_text_field( $_GET['campaign'] ) : '' // phpcs:ignore WordPress.Security
	// );
	//
	// if ( ! $visit_data instanceof Visit ) {
	// return;
	// }
	//
	// $visit_cookie_name = wca_get_visit_cookie_name();
	// $cookie_expiry     = wca_get_cookie_expiry();
	//
	// setcookie( $visit_cookie_name, $visit_data->get_id(), time() + $cookie_expiry, '/' );
	//
	// $_COOKIE[ $visit_cookie_name ] = $visit_data->get_id();
	//
	// **
	// * Action hook fired after visit tracking.
	// *
	// * @param int $user_id User ID.
	// * @param Visit $visit_data Visit data.
	// */
	// do_action( 'wc_affiliate_track_visit_after', $user->ID, $visit_data );
	// }

	/**
	 * Verify user email
	 *
	 * @since  2.0.2
	 * @author Jakaria Istauk <jakariamd35@gmail.com>
	 */
	public function verify_email() {
		if ( ! wca_is_email_validation_enabled() ) {
			return;
		}

		if ( ! isset( $_GET['validate'] ) ) { // phpcs:ignore WordPress.Security.NonceVerification.Recommended
			return;
		}

		$validate = sanitize_text_field( wp_unslash( $_GET['validate'] ) ); // phpcs:ignore WordPress.Security.NonceVerification.Recommended
		if ( '' === $validate ) {
			return;
		}

		$validation_data = wca_ncrypt()->decrypt( $validate );
		$validation_data = json_decode( $validation_data );

		if ( ! $validation_data ) {
			return;
		}

		$expiry_time = wca_get_email_validation_expiry();
		$time_dif    = time() - $validation_data->time;

		if ( $time_dif > $expiry_time ) {
			return;
		}

		$status = wca_is_auto_approve_enabled() ? 'active' : 'pending';

		// Use User model for meta updates.
		$user_model = new User( $validation_data->id );
		$user_model->update_meta( '_wc_affiliate_status', $status );
		$user_model->update_meta( '_wc_affiliate_email_verified', true );
	}

	/**
	 * Add credit for WooCommerce orders
	 *
	 * @param int $order_id Order ID.
	 */
	public function add_wc_credit( int $order_id ) {
		/**
		 * Action hook fired before adding WC credit.
		 *
		 * @param int $order_id Order ID.
		 */
		do_action( 'wc_affiliate_add_wc_credit_before', $order_id );

		$order = wc_get_order( $order_id );
		if ( ! $order instanceof WC_Order ) {
			return;
		}

		if ( ! empty( $order->get_meta( '_wc_affiliate_credited' ) ) ) {
			return;
		}

		$users = wca_get_affiliate_for_credit_from_wc_order( $order );
		$users = $this->get_allowed_users( $users, $order );
		if ( ! $users ) {
			return;
		}

		$cookie_name   = wca_get_cookie_name();
		$_cookie_visit = wca_get_visit_cookie_name();
		$visit_id      = isset( $_COOKIE[ $_cookie_visit ] ) ? sanitize_text_field( wp_unslash( $_COOKIE[ $_cookie_visit ] ) ) : 0;

		// Determine payment status based on order status.
		$order_status   = $order->get_status();
		$payment_status = wca_get_option( 'basic', "referral_status.{$order_status}", 'pending' );

		foreach ( $users as $_user ) {
			/**
			 * Action hook fired before processing WC credit for individual affiliate.
			 *
			 * @param int $user_id Affiliate user ID.
			 * @param int $order_id Order ID.
			 * @param WC_Order $order Order object.
			 * @param int $visit_id Visit ID.
			 */
			do_action( 'wc_affiliate_add_wc_credit_per_affiliate_before', $_user->ID, $order_id, $order, $visit_id );

			$commission_data = wca_wc_calculate_commissions( $order, $_user->ID );

			/**
			 * Filter to modify WC commission data per affiliate.
			 *
			 * @param array $commission_data Commission data array.
			 * @param int $user_id Affiliate user ID.
			 * @param int $order_id Order ID.
			 * @param WC_Order $order Order object.
			 */
			$commission_data = apply_filters( 'wc_affiliate_wc_commission_data_per_affiliate', $commission_data, $_user->ID, $order_id, $order );

			$commission = $commission_data['total_commission'] ?? 0;
			$products   = $commission_data['products'] ?? array();

			/**
			 * Filter to modify WC commission amount per affiliate.
			 *
			 * @param float $commission Commission amount.
			 * @param int $user_id Affiliate user ID.
			 * @param int $order_id Order ID.
			 * @param WC_Order $order Order object.
			 * @param array $products Order products.
			 */
			$commission = apply_filters( 'wc_affiliate_wc_commission_amount_per_affiliate', $commission, $_user->ID, $order_id, $order, $products );

			if ( $commission <= 0 ) {
				/**
				 * Action hook fired when WC commission is zero or negative for affiliate.
				 *
				 * @param int $user_id Affiliate user ID.
				 * @param int $order_id Order ID.
				 * @param WC_Order $order Order object.
				 * @param float $commission Commission amount.
				 * @param array $commission_data Commission data.
				 */
				do_action( 'wc_affiliate_add_wc_credit_per_affiliate_zero_commission', $_user->ID, $order_id, $order, $commission, $commission_data );
				continue;
			}

			/**
			 * Filter to modify WC payment status per affiliate.
			 *
			 * @param string $payment_status Payment status.
			 * @param int $user_id Affiliate user ID.
			 * @param int $order_id Order ID.
			 * @param WC_Order $order Order object.
			 */
			$payment_status_filtered = apply_filters( 'wc_affiliate_wc_payment_status_per_affiliate', $payment_status, $_user->ID, $order_id, $order );

			// Add as a referral credit.
			$referral_id = wca_insert_credit( $_user->ID, $commission, 'sale', $visit_id, $order_id, $products, $order->get_total(), $payment_status_filtered );

			$visit_model = new Visit( $visit_id );
			$visit_model->update(
				array(
					'referral' => $referral_id,
				)
			);

			// update the order.
			$order->update_meta_data( '_wc_affiliate_credited', $commission );
			$order->save();

			$admin_url    = admin_url( 'admin.php?page=wc-affiliate#/referrals' );
			$referral_url = add_query_arg( 'referral', $referral_id, $admin_url );

			$affiliate = get_user_by( wca_get_token_type(), $_user->ID );

			/**
			 * Filter to modify WC order note per affiliate.
			 *
			 * @param string $order_note Order note text.
			 * @param int $user_id Affiliate user ID.
			 * @param int $referral_id Referral ID.
			 * @param float $commission Commission amount.
			 * @param string $referral_url Referral admin URL.
			 * @param WP_User $affiliate Affiliate user object.
			 */
			$order_note = apply_filters(
				'wc_affiliate_wc_order_note_per_affiliate',
				sprintf( '%s affiliate commission assigned to <a href="%s">%s</a>!', wc_price( $commission, array( 'decimals' => 2 ) ), $referral_url, $affiliate->display_name ),
				$_user->ID,
				$referral_id,
				$commission,
				$referral_url,
				$affiliate
			);

			$order->add_order_note( $order_note );

			/**
			 * Action hook fired after processing WC credit for individual affiliate.
			 *
			 * @param int $user_id Affiliate user ID.
			 * @param int $order_id Order ID.
			 * @param int $referral_id Referral ID.
			 * @param float $commission Commission amount.
			 * @param WC_Order $order Order object.
			 */
			do_action( 'wc_affiliate_add_wc_credit_per_affiliate_after', $_user->ID, $order_id, $referral_id, $commission, $order );
		}

		// should we remove cookies once the order is placed?
		if ( wca_credit_once() ) {
			setcookie( $cookie_name, 0, time() - 1, COOKIEPATH, COOKIE_DOMAIN );
			setcookie( $_cookie_visit, 0, time() - 1, COOKIEPATH, COOKIE_DOMAIN );
		}

		/**
		 * Action hook fired after adding WC credit.
		 *
		 * @param int $order_id Order ID.
		 * @param array $user_ids Affiliate user IDs.
		 */
		do_action( 'wc_affiliate_add_wc_credit_after', $order_id, $users );
	}

	/**
	 * Add credit for EasyCommerce orders
	 *
	 * @param int $order_id Order ID.
	 */
	public function add_ec_credit( int $order_id ) {
		if ( ! empty( get_post_meta( $order_id, '_wc_affiliate_credited', true ) ) ) {
			return;
		}

		$order = new \EasyCommerce\Models\Order( $order_id );
		if ( ! $order->exists() ) {
			return;
		}

		$users = wca_get_affiliate_for_credit_from_ec_order( $order );
		$users = $this->get_allowed_users( $users, $order );
		if ( ! $users ) {
			return;
		}

		$cookie_name   = wca_get_cookie_name();
		$_cookie_visit = wca_get_visit_cookie_name();
		$visit_id      = isset( $_COOKIE[ $_cookie_visit ] ) ? sanitize_text_field( wp_unslash( $_COOKIE[ $_cookie_visit ] ) ) : 0;

		// Determine payment status based on order status.
		$order_status   = $order->get_status();
		$payment_status = wca_get_option( 'basic', "referral_status.{$order_status}", 'pending' );

		foreach ( $users as $_user ) {
			/**
			 * Action hook fired before processing EC credit for individual affiliate.
			 *
			 * @param int $user_id Affiliate user ID.
			 * @param int $order_id Order ID.
			 * @param object $order Order object.
			 * @param int $visit_id Visit ID.
			 */
			do_action( 'wc_affiliate_add_ec_credit_per_affiliate_before', $_user->ID, $order_id, $order, $visit_id );

			$commission_data = wca_ec_calculate_commissions( $order, $_user->ID );

			/**
			 * Filter to modify EC commission data per affiliate.
			 *
			 * @param array $commission_data Commission data array.
			 * @param int $user_id Affiliate user ID.
			 * @param int $order_id Order ID.
			 * @param object $order Order object.
			 */
			$commission_data = apply_filters( 'wc_affiliate_ec_commission_data_per_affiliate', $commission_data, $_user->ID, $order_id, $order );

			$commission = $commission_data['total_commission'];

			/**
			 * Filter to modify EC commission amount per affiliate.
			 *
			 * @param float $commission Commission amount.
			 * @param int $user_id Affiliate user ID.
			 * @param int $order_id Order ID.
			 * @param object $order Order object.
			 * @param array $products Order products.
			 */
			$commission = apply_filters( 'wc_affiliate_ec_commission_amount_per_affiliate', $commission, $_user->ID, $order_id, $order, $commission_data['products'] ?? array() );

			if ( $commission <= 0 ) {
				/**
				 * Action hook fired when EC commission is zero or negative for affiliate.
				 *
				 * @param int $user_id Affiliate user ID.
				 * @param int $order_id Order ID.
				 * @param object $order Order object.
				 * @param float $commission Commission amount.
				 * @param array $commission_data Commission data.
				 */
				do_action( 'wc_affiliate_add_ec_credit_per_affiliate_zero_commission', $_user->ID, $order_id, $order, $commission, $commission_data );
				continue;
			}

			/**
			 * Filter to modify EC payment status per affiliate.
			 *
			 * @param string $payment_status Payment status.
			 * @param int $user_id Affiliate user ID.
			 * @param int $order_id Order ID.
			 * @param object $order Order object.
			 */
			$payment_status_filtered = apply_filters( 'wc_affiliate_ec_payment_status_per_affiliate', $payment_status, $_user->ID, $order_id, $order );

			// Add as a referral credit.
			$credit_id = wca_insert_credit( $_user->ID, $commission, 'sale', $visit_id, $order_id, $commission_data['products'], $order->get_total(), $payment_status_filtered );

			$visit_model = new Visit( $visit_id );
			$visit_model->update(
				array(
					'referral' => $credit_id,
				)
			);

			// update the order.
			update_post_meta( $order_id, '_wc_affiliate_credited', $commission );

			// $admin_url    = admin_url( 'admin.php?page=wc-affiliate#/referrals' );
			// $referral_url = add_query_arg( 'referral', $credit_id, $admin_url );
			// $affiliate    = get_user_by( wca_get_token_type(), $_user->ID );

			/**
			 * Filter to modify EC order note per affiliate.
			 *
			 * @param string $order_note Order note text.
			 * @param int $user_id Affiliate user ID.
			 * @param int $credit_id Credit/referral ID.
			 * @param float $commission Commission amount.
			 * @param string $referral_url Referral admin URL.
			 * @param WP_User $affiliate Affiliate user object.
			 */
			// $order_note = apply_filters(
			// 'wc_affiliate_ec_order_note_per_affiliate',
			// sprintf( '%s affiliate commission assigned to <a href="%s">%s</a>!', wc_price( $commission, array( 'decimals' => 2 ) ), $referral_url, $affiliate->display_name ),
			// $user_id,
			// $credit_id,
			// $commission,
			// $referral_url,
			// $affiliate
			// );

			// $order_note_mode = new Order_Notes();
			// $order_note_mode->add( $order_id, 'private', $order_note );

			/**
			 * Action hook fired after processing EC credit for individual affiliate.
			 *
			 * @param int $user_id Affiliate user ID.
			 * @param int $order_id Order ID.
			 * @param int $credit_id Credit/referral ID.
			 * @param float $commission Commission amount.
			 * @param object $order Order object.
			 */
			do_action( 'wc_affiliate_add_ec_credit_per_affiliate_after', $_user->ID, $order_id, $credit_id, $commission, $order );
		}

		// should we remove cookies once the order is placed?
		if ( wca_credit_once() ) {
			setcookie( $cookie_name, 0, time() - 1, COOKIEPATH, COOKIE_DOMAIN );
			setcookie( $_cookie_visit, 0, time() - 1, COOKIEPATH, COOKIE_DOMAIN );
		}

		/**
		 * Action hook fired after adding WC credit.
		 *
		 * @param int $order_id Order ID.
		 * @param array $user_ids Affiliate user IDs.
		 */
		do_action( 'wc_affiliate_add_ec_credit_after', $order_id, $users );
	}

	/**
	 * Filter allowed users by removing self-referrals based on configuration
	 *
	 * Filters the array of affiliate users to exclude self-referrals if not permitted.
	 * Compares the customer ID from the order against each affiliate user ID.
	 *
	 * @since 1.0.0
	 *
	 * @param array  $users Array of WP_User objects representing potential affiliates.
	 * @param object $order Order object (WC_Order or EasyCommerce Order).
	 *
	 * @return WP_User[] Filtered array of WP_User objects with self-referrals removed if applicable.
	 */
	protected function get_allowed_users( array $users, object $order ): array {
		// Hoist invariants outside the filter — computed once.
		$allow_self_referral = wca_allow_self_referral();
		$customer_id         = (int) $order->get_customer_id();

		return array_filter(
			$users,
			function ( $_user ) use ( $allow_self_referral, $customer_id ) {
				return $customer_id !== (int) $_user->ID || $allow_self_referral;
			}
		);
	}

	/**
	 * Apply affiliate discount
	 */
	public function apply_discount() {
		$cookie_name = wca_get_cookie_name();
		if ( ! isset( $_COOKIE[ $cookie_name ] ) || ! wca_is_referred_discount_enabled() ) {
			return;
		}

		$token = sanitize_text_field( $_COOKIE[ $cookie_name ] ); // phpcs:ignore WordPress.Security
		$user  = wca_get_affiliate_user_by_token( $token );

		if ( ! $user instanceof WP_User ) {
			return;
		}

		// Apply discount logic would go here
		// This would integrate with WooCommerce coupon system.
	}

	/**
	 * Handle subscription renewal orders
	 *
	 * Processes recurring commissions for WooCommerce subscription renewal orders.
	 * Creates a new referral credit for the affiliate based on the original subscription order.
	 *
	 * @since 1.0.0
	 *
	 * @param \WC_Subscription $subscription The subscription object being renewed.
	 * @param WC_Order         $last_order   The renewal order object.
	 *
	 * @return void
	 */
	public function reorder_subscription( $subscription, $last_order ) {
		if ( ! wca_is_recurring_order_enabled() ) {
			return;
		}

		// Find original referral for this subscription.
		global $wpdb;
		$parent_order_id = $last_order->get_parent_id();

		if ( ! $parent_order_id ) {
			return;
		}

		$referral = $wpdb->get_row(
			$wpdb->prepare(
				"SELECT * FROM {$wpdb->prefix}wca_referrals WHERE order_id = %d",
				$parent_order_id
			)
		);

		if ( ! $referral ) {
			return;
		}

		$order_id    = $last_order->get_id();
		$order_total = $last_order->get_total();
		$items       = $last_order->get_items();
		$products    = array();

		foreach ( $items as $item ) {
			$products[ $item->get_product_id() ] = $item->get_name();
		}

		// Calculate recurring commission using dedicated recurring settings.
		$commission_model = new \WC_Affiliate\Models\Commission();
		$total_commission = $commission_model->calculate_recurring_commission( $last_order, $referral->affiliate );

		// Insert recurring commission.
		wca_insert_credit(
			$referral->affiliate,
			$total_commission,
			'recurring',
			0,
			$order_id,
			$products,
			$order_total,
			'pending'
		);
	}
}
