<?php
/**
 * Fast Events Login controller.
 *
 * @since 1.3
 */

declare( strict_types=1 );
namespace FeData\FastEvents\RestAPI;

defined( 'ABSPATH' ) || exit;

use FeData\FastEvents\Helpers\AuthHelper;
use FeData\FastEvents\Logging\LoggerFactory;
use FeData\FastEvents\Payment\PaymentFactory;
use FeData\FastEvents\Storage\Options;
use FeData\FastEvents\Storage\PluginSettings;
use FeData\FastEvents\Storage\UserMeta;
use WP_Error;
use WP_REST_Request;
use WP_REST_Response;
use WP_REST_Server;

/**
 * Fast Events login class.
 */
class LoginController {

	private const FAST_EVENTS_ADMIN_API_VERSION = 9;
	private const NAMESPACE                     = 'fast-events/v1';
	private const LOGIN_ROUTE                   = '/admin/login';

	/**
	 * Fast Events login constructor.
	 *
	 * @param PluginSettings $settings Settings of this plugin.
	 * @param AuthHelper     $auth     Auth helper.
	 *
	 * @since 1.3
	 */
	public function __construct( private readonly PluginSettings $settings, private readonly AuthHelper $auth ) {}


	/**
	 * Register the routes for the objects of the controller.
	 *
	 * @since 1.3
	 */
	public function register_routes(): void {

		// Login.
		register_rest_route(
			self::NAMESPACE,
			self::LOGIN_ROUTE,
			array(
				'methods'             => WP_REST_Server::CREATABLE,
				'callback'            => array( $this, 'login_callback' ),
				'permission_callback' => function () {
					return $this->auth->authorize( $this->auth::NO_PERMISSION_NEEDED );
				},
				'args'                => array(
					'api_version' => array(
						'required'          => true,
						'type'              => 'integer',
						'sanitize_callback' => 'absint',
					),
				),
			)
		);

		// Verify OAUTH2 result.
		register_rest_route(
			self::NAMESPACE,
			self::LOGIN_ROUTE . '/verify',
			array(
				'methods'             => WP_REST_Server::CREATABLE,
				'callback'            => array( $this, 'verify_callback' ),
				'permission_callback' => function () {
					return $this->auth->authorize( $this->auth::NO_PERMISSION_NEEDED );
				},
			)
		);
	}


	/**
	 * Login simulation. There is no real login; just using it to validate the authentication (application password and API key)
	 *
	 * @since 1.0
	 * @since 1.4 SaaS enabled
	 * @since 1.5 Introduced API version number
	 * @since 1.6 - Removed getting merchant name
	 *            - Pass list of permissions to the client
	 * @since 1.8.3 Add a list of allowed events
	 * @since 1.8.4 Don't include even_type 0
	 * @since 2.4.0 Improved the error message in case of wrong API level
	 * @since 2.5.0 Optionally decrypt the saas information.
	 *
	 * @param WP_REST_Request $data Request instance.
	 *
	 * @return WP_REST_Response|WP_Error
	 */
	public function login_callback( WP_REST_Request $data ): WP_Error|WP_REST_Response {
		global $wpdb;
		global $fevt_container;

		$result = array(
			'saas'            => false,
			'saas_fee'        => $this->settings->saas_client_fee(),
			'saas_fee_per'    => 1 === $this->settings->saas_client_fee_per() ? 'order' : 'ticket',
			'provider'        => $fevt_container->get( PaymentFactory::class )->get_provider_name(),
			'currency'        => $this->settings->currency(),
			'currency_symbol' => $this->settings->currency_symbol(),
			'enabled'         => false,
			'url'             => '',
			'blog'            => ( get_bloginfo( 'name' ) ),
			'permissions'     => $this->auth->get_permissions(),
			'is_admin'        => $this->auth->is_admin_user(),
			'account_id'      => wp_get_current_user()->ID,
			'custom_status'   => $this->settings->misc_custom_order_status(),
			'api_version'     => self::FAST_EVENTS_ADMIN_API_VERSION,
		);

		// Check the API version.
		if ( self::FAST_EVENTS_ADMIN_API_VERSION > absint( $data['api_version'] ) ) {
			return new WP_Error( 'api-version_conflict', __( 'Please upgrade the Management Interface (FE Admin App) to version: ', 'fast-events' ) . fast_events_func()::FE_ADMIN_VERSION, array( 'status' => 404 ) );
		}

		// Get all events the user is authorized for.
		$auth_query       = $this->auth->get_restricted_events( $this->auth::FAST_EVENTS_AUTH_QUERY_EVENTS );
		$result['events'] = $wpdb->get_results(
			$wpdb->prepare(
				"SELECT id, event_name FROM {$wpdb->prefix}fe_events " .
				( empty( $auth_query ) ? 'WHERE event_type != 0' : ( $auth_query . ' AND event_type != 0' ) ) . ' ORDER BY id DESC' // phpcs:ignore
			)
		);

		// Is SaaS mode enabled?
		if ( ! $this->settings->saas_mode() ) {
			return rest_ensure_response( $result );
		}
		$result['saas'] = true;

		// Is this an admin user?
		if ( $this->auth->is_admin_user() ) {
			return rest_ensure_response( $result );
		}

		// Has SaaS been enabled for this user?
		$user   = wp_get_current_user();
		$config = $fevt_container->get( UserMeta::class )->get_saas_config( $user->ID );
		if ( ! empty( $config ) ) {

			// Get a fresh token for a 'ping', so we know for sure we are still authorized.
			$token = $fevt_container->get( PaymentFactory::class )->get_access_token( $user->ID );
			if ( empty( $token ) ) {
				$fevt_container->get( LoggerFactory::class )->warning(
					'Admin App - login, Got empty access token',
					array(
						'type' => 'Login',
						'id'   => $user->ID,
						'name' => $user->display_name,
					)
				);
				$result['url'] = $fevt_container->get( PaymentFactory::class )->get_oauth_url( $user );
				return rest_ensure_response( $result );
			}
			$result['enabled'] = true;
			return rest_ensure_response( $result );
		}

		$result['url'] = $fevt_container->get( PaymentFactory::class )->get_oauth_url( $user );
		return rest_ensure_response( $result );
	}

	/**
	 * Verify the result of the OAUTH2 request.
	 *
	 * @since 1.4
	 * @since 2.5.0 Optionally decrypt the saas information.
	 *
	 * @return WP_REST_Response|WP_Error
	 */
	public function verify_callback(): WP_Error|WP_REST_Response {
		global $fevt_container;

		$result = array(
			'saas'    => true,
			'enabled' => false,
			'error'   => '',
		);

		// Is SaaS mode enabled?
		if ( ! $this->settings->saas_mode() ) {
			$result['saas'] = false;
			return rest_ensure_response( $result );
		}

		// Has SaaS been enabled for this user?
		$user   = wp_get_current_user();
		$config = $fevt_container->get( UserMeta::class )->get_saas_config( $user->ID );
		if ( ! empty( $config ) ) {

			// Get a fresh token for a 'ping', so we know for sure we are still authorised.
			$token = $fevt_container->get( PaymentFactory::class )->get_access_token( $user->ID );
			if ( is_wp_error( $token ) ) {
				$result['error'] = ( $token->get_error_message() );
				return rest_ensure_response( $result );
			}
			$result['enabled'] = true;
		}

		// Check if there was an SaaS error.
		$error = $fevt_container->get( Options::class )->get_saas_error();
		if ( false !== $error ) {
			$result['error'] = ( $error );
			$fevt_container->get( Options::class )->delete_saas_error();
		}

		return rest_ensure_response( $result );
	}
}
