<?php
/**
 * Manage Billing
 *
 * @package Tutor\Ecommerce
 * @author Themeum
 * @link https://themeum.com
 * @since 3.0.0
 */

namespace Tutor\Ecommerce;

use stdClass;
use TUTOR\Icon;
use TUTOR\BaseController;
use Tutor\Helpers\HttpHelper;
use Tutor\Helpers\ValidationHelper;
use Tutor\Models\BillingModel;
use Tutor\Traits\JsonResponse;

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

/**
 * BillingController class
 *
 * @since 3.0.0
 */
class BillingController extends BaseController {


	/**
	 * Billing model
	 *
	 * @since 3.0.0
	 *
	 * @var BillingModel
	 */
	private $model;

	/**
	 * Trait for sending JSON response
	 */
	use JsonResponse;

	/**
	 * Constructor.
	 *
	 * Initializes the Billing class, sets the page title, and optionally registers
	 * hooks for handling AJAX requests related to billing data.
	 *
	 * @param bool $register_hooks Whether to register hooks for handling requests. Default is true.
	 *
	 * @since 3.0.0
	 *
	 * @return void
	 */
	public function __construct( $register_hooks = true ) {
		$this->model = new BillingModel();

		if ( $register_hooks ) {
			add_filter( 'tutor_dashboard/nav_items/settings/nav_items', array( $this, 'register_nav' ) );
			add_filter( 'load_dashboard_template_part_from_other_location', array( $this, 'load_template' ) );

			/**
			 * Handle AJAX request for saving billing info if current user.
			 *
			 * @since 3.0.0
			 */
			add_action( 'wp_ajax_tutor_save_billing_info', array( $this, 'save_billing_info' ) );

			/**
			 * Handle AJAX request for getting billing info if current user.
			 *
			 * @since 3.0.0
			 */
			add_action( 'wp_ajax_tutor_get_billing_info', array( $this, 'get_billing_info' ) );
		}
	}

	/**
	 * Register billing nav menu for settings
	 *
	 * @since 3.0.0
	 * @since 4.0.0 update tabs order and data structure.
	 *
	 * @param array $tabs setting navigation tabs.
	 *
	 * @return array
	 */
	public static function register_nav( $tabs ) {
		$id = 'billing-address';

		$new_tab = array(
			'id'       => $id,
			'label'    => 'Billing Address',
			'icon'     => Icon::BILLING,
			'text'     => __( 'Your payment address', 'tutor' ),
			'template' => 'ecommerce.billing',
			'role'     => false,
		);

		$position = array_search( 'social-accounts', array_keys( $tabs ), true );

		if ( false === $position ) {
			$tabs[ $id ] = $new_tab;
			return $tabs;
		}

		return array_slice( $tabs, 0, $position + 1, true )
		+ array( $id => $new_tab )
		+ array_slice( $tabs, $position + 1, null, true );
	}

	/**
	 * Load billing template for settings
	 *
	 * Based on query_vars filter template path
	 *
	 * @since 3.0.0
	 *
	 * @param string $location default file location.
	 *
	 * @return string
	 */
	public static function load_template( $location ) {
		$page_name          = get_query_var( 'pagename' );
		$dashboard_sub_page = get_query_var( 'tutor_dashboard_sub_page' );

		$dashboard_page_id = (int) tutor_utils()->get_option( 'tutor_dashboard_page_id' );
		$dashboard_page    = get_post( $dashboard_page_id );

		// Current page is dashboard & sub page is billing.
		if ( $page_name === $dashboard_page->post_name && 'billing' === $dashboard_sub_page ) {
			$template = tutor()->path . 'templates/ecommerce/billing.php';

			if ( file_exists( $template ) ) {
				$location = $template;
			}
		}

		return $location;
	}

	/**
	 * Get the customer model object
	 *
	 * @since 3.0.0
	 *
	 * @return object
	 */
	public function get_model() {
		return $this->model;
	}

	/**
	 * Save billing information for the current user.
	 *
	 * @since 3.0.0
	 *
	 * @return void
	 */
	public function save_billing_info() {
		if ( ! tutor_utils()->is_nonce_verified() ) {
			$this->json_response(
				tutor_utils()->error_message( 'nonce' ),
				null,
				HttpHelper::STATUS_BAD_REQUEST
			);
		}

		$data = $this->get_allowed_fields( $_POST ); // phpcs:ignore WordPress.Security.NonceVerification.Missing

		$user_id         = get_current_user_id();
		$data['user_id'] = $user_id;

		$validation = $this->validate( $data );
		if ( ! $validation->success ) {
			$this->json_response(
				__( 'Invalid inputs', 'tutor' ),
				$validation->errors,
				HttpHelper::STATUS_UNPROCESSABLE_ENTITY
			);
		}

		$billing_info = $this->get_billing_info();

		if ( $billing_info ) {
			$response = $this->model->update( $data, array( 'user_id' => $user_id ) );
		} else {
			$response = $this->model->insert( $data );
		}

		if ( ! $response ) {
			$this->json_response(
				__( 'Failed to save billing info', 'tutor' ),
				null,
				HttpHelper::STATUS_INTERNAL_SERVER_ERROR
			);
		}

		$this->json_response( __( 'Billing info saved successfully', 'tutor' ) );
	}

	/**
	 * Get billing information for the current user.
	 *
	 * @since 3.0.0
	 *
	 * @param int $user_id User id.
	 *
	 * @return mixed The user's billing information.
	 */
	public function get_billing_info( $user_id = 0 ) {
		$user_id = tutor_utils()->get_user_id( $user_id );
		return $this->model->get_info( $user_id );
	}

	/**
	 * Validate input data based on predefined rules.
	 *
	 * This protected method validates the provided data array against a set of
	 * predefined validation rules. The rules specify that 'order_id' is required
	 * and must be numeric. The method will skip validation rules for fields that
	 * are not present in the data array.
	 *
	 * @since 3.0.0
	 *
	 * @param array $data The data array to validate.
	 *
	 * @return object The validation result. It returns validation object.
	 */
	protected function validate( array $data ) {

		$validation_rules = array(
			'user_id'    => 'required|numeric',
			'first_name' => 'required',
			'last_name'  => 'required',
			'email'      => 'required|email',
			'phone'      => 'required',
			'zip_code'   => 'required',
			'address'    => 'required',
			'country'    => 'required',
			'state'      => 'required',
			'city'       => 'required',
		);

		// Skip validation rules for not available fields in data.
		foreach ( $validation_rules as $key => $value ) {
			if ( ! array_key_exists( $key, $data ) ) {
				unset( $validation_rules[ $key ] );
			}
		}

		return ValidationHelper::validate( $validation_rules, $data );
	}

	/**
	 * Get country and state options for billing information.
	 *
	 * @since 4.0.0
	 *
	 * @return object An object containing country and state options.
	 */
	public static function get_country_state_options() {
		$countries       = tutor_get_country_list();
		$country_options = array();
		$state_mapping   = array();

		foreach ( $countries as $country ) {
			array_push(
				$country_options,
				array(
					'label' => $country['name'],
					'value' => $country['name'],
				)
			);

			if ( ! empty( $country['states'] ) ) {
				$state_mapping[ $country['name'] ] = array_map(
					function ( $state ) {
						return array(
							'label' => $state['name'],
							'value' => $state['name'],
						);
					},
					$country['states']
				);
			}
		}

		$obj                  = new stdClass();
		$obj->country_options = $country_options;
		$obj->state_options   = $state_mapping;

		return $obj;
	}

	/**
	 * Get default values for billing form.
	 *
	 * @since 4.0.0
	 *
	 * @return array An array containing default values for billing information.
	 */
	public static function get_default_values() {
		$billing_info    = ( new BillingController() )->get_billing_info();
		$billing_country = $billing_info->billing_country ?? tutor_utils()->input_old( 'billing_country', '' );

		$default_values = array(
			'billing_first_name' => $billing_info->billing_first_name ?? '',
			'billing_last_name'  => $billing_info->billing_last_name ?? '',
			'billing_email'      => $billing_info->billing_email ?? '',
			'billing_country'    => $billing_country,
			'billing_state'      => $billing_info->billing_state ?? '',
			'billing_city'       => $billing_info->billing_city ?? '',
			'billing_phone'      => $billing_info->billing_phone ?? '',
			'billing_zip_code'   => $billing_info->billing_zip_code ?? '',
			'billing_address'    => $billing_info->billing_address ?? '',
		);

		return $default_values;
	}
}
