<?php

namespace lemonsqueezy;

/**
 * Class to handle the rest api requests of the lemon squeezy plugin.
 */
class LSQ_Rest_Controller {
	/**
	 * Contains instance or null
	 *
	 * @var object|null
	 */
	private static $instance = null;

	/**
	 * Returns instance of LSQ_Rest_Controller.
	 *
	 * @return object
	 */
	public static function get_instance() {

		if ( null === self::$instance ) {
			self::$instance = new self();
		}

		return self::$instance;
	}

	/**
	 * Constructor for LSQ_Rest_Controller.
	 */
	public function __construct() {
		add_action( 'rest_api_init', array( $this, 'register_routes' ) );
	}

	/**
	 * Register the routes for the objects of the controller.
	 */
	public function register_routes() {
		$namespace = 'lsq/v1';

		register_rest_route(
			$namespace,
			'/validate/',
			array(
				'methods'             => \WP_REST_Server::READABLE,
				'callback'            => array( $this, 'validate_key' ),
				'args'                => array(),
				'permission_callback' => function () {
					return true;
				},
			)
		);

		register_rest_route(
			$namespace,
			'/delete_test_key/',
			array(
				'methods'             => \WP_REST_Server::DELETABLE,
				'callback'            => array( $this, 'delete_test' ),
				'args'                => array(),
				'permission_callback' => function () {
					return current_user_can( 'manage_options' );
				},
			)
		);

		register_rest_route(
			$namespace,
			'/save_test_key/',
			array(
				'methods'             => \WP_REST_Server::CREATABLE,
				'callback'            => array( $this, 'save_test' ),
				'args'                => array(
					'test_key' => array(
						'description'       => 'Test API key.',
						'type'              => 'string',
						'required'          => true,
						'sanitize_callback' => 'sanitize_text_field',
					),
				),
				'permission_callback' => function () {
					return current_user_can( 'manage_options' );
				},
			)
		);

		register_rest_route(
			$namespace,
			'/activate/',
			array(
				'methods'             => \WP_REST_Server::READABLE,
				'callback'            => array( $this, 'activate_key' ),
				'args'                => array(
					'license_key'   => array(
						'description'       => 'License key.',
						'type'              => 'string',
						'required'          => true,
						'sanitize_callback' => 'sanitize_text_field',
					),
					'instance_name' => array(
						'description'       => 'Instance name for the activation.',
						'type'              => 'string',
						'required'          => true,
						'sanitize_callback' => 'sanitize_text_field',
					),
				),
				'permission_callback' => function () {
					return true;
				},
			)
		);

		register_rest_route(
			$namespace,
			'/deactivate/',
			array(
				'methods'             => \WP_REST_Server::READABLE,
				'callback'            => array( $this, 'deactivate_key' ),
				'args'                => array(
					'license_key' => array(
						'description'       => 'License key.',
						'type'              => 'string',
						'required'          => true,
						'sanitize_callback' => 'sanitize_text_field',
					),
					'instance_id' => array(
						'description'       => 'Instance ID of the existing activation.',
						'type'              => 'string',
						'required'          => true,
						'sanitize_callback' => 'sanitize_text_field',
					),
				),
				'permission_callback' => function () {
					return true;
				},
			)
		);

		register_rest_route(
			$namespace,
			'/stores/',
			array(
				'methods'             => \WP_REST_Server::READABLE,
				'callback'            => array( $this, 'get_stores' ),
				'args'                => array(),
				'permission_callback' => function () {
					return true;
				},
			)
		);

		register_rest_route(
			$namespace,
			'/products/',
			array(
				'methods'             => \WP_REST_Server::READABLE,
				'callback'            => array( $this, 'get_products' ),
				'args'                => array(),
				'permission_callback' => function () {
					return true;
				},
			)
		);

		register_rest_route(
			$namespace,
			'/update/',
			array(
				'methods'             => \WP_REST_Server::READABLE,
				'callback'            => array( $this, 'get_update' ),
				'args'                => array(),
				'permission_callback' => function () {
					return true;
				},
			)
		);
	}

	/**
	 * Delete Test API key.
	 *
	 * @param \WP_REST_Request $request Full data about the request.
	 * @return \WP_Error|\WP_REST_Response
	 */
	public function delete_test() {

		$deleted = delete_option( 'lsq_api_key_test' );

		return new \WP_REST_Response(
			array(
				'success' => $deleted,
			),
			$deleted ? 200 : 400
		);
	}

	/**
	 * Save Test API key with Lemon Squeezy API.
	 *
	 * @param \WP_REST_Request $request Full data about the request.
	 * @return \WP_Error|\WP_REST_Response
	 */
	public function save_test( $request ) {
		$test_key = $request->get_param( 'test_key' );

		$response = wp_remote_get(
			LSQ_API_URL . '/v1/users/me',
			array(
				'headers' => array(
					'Authorization' => 'Bearer ' . $test_key,
					'Accept'        => 'application/vnd.api+json',
					'Content-Type'  => 'application/vnd.api+json',
					'Cache-Control' => 'no-cache',
				),
			)
		);

		$is_valid = false;

		if ( ! is_wp_error( $response ) ) {
			if ( 200 === wp_remote_retrieve_response_code( $response ) ) {
				$is_valid = true;

				$body = json_decode( $response['body'] );
				$user = $body->data;
				update_option( 'lsq_api_key_test', $test_key );
			} else {
				$error_message = wp_remote_retrieve_response_message( $response );
			}
		} else {
			$error_message = $response->get_error_message();
		}

		return new \WP_REST_Response(
			array(
				'success' => $is_valid,
				'user'    => $user,
				'error'   => $error_message,
			),
			$is_valid ? 200 : 400
		);
	}

	/**
	 * Validate API key with Lemon Squeezy API.
	 *
	 * @param \WP_REST_Request $request Full data about the request.
	 * @return \WP_Error|\WP_REST_Response
	 */
	public function validate_key() {
		// Check LS API connection.
		$api_key       = get_option( 'lsq_api_key' );
		$is_valid      = false;
		$user          = null;
		$error_message = '';

		if ( ! isset( $api_key ) || empty( $api_key ) ) {
			return new \WP_REST_Response(
				array(
					'success' => $is_valid,
					'user'    => $user,
					'error'   => __( 'Unauthorized request', 'lemon-squeezy' ),
				),
				401
			);
		}

		$response = wp_remote_get(
			LSQ_API_URL . '/v1/users/me',
			array(
				'headers' => array(
					'Authorization' => 'Bearer ' . $api_key,
					'Accept'        => 'application/vnd.api+json',
					'Content-Type'  => 'application/vnd.api+json',
					'Cache-Control' => 'no-cache',
				),
			)
		);

		if ( ! is_wp_error( $response ) ) {
			if ( 200 === wp_remote_retrieve_response_code( $response ) ) {
				$is_valid = true;

				$body = json_decode( $response['body'] );
				$user = $body->data;
			} else {
				$error_message = wp_remote_retrieve_response_message( $response );
			}
		} else {
			$error_message = $response->get_error_message();
		}

		return new \WP_REST_Response(
			array(
				'success' => $is_valid,
				'user'    => $user,
				'error'   => $error_message,
			),
			$is_valid ? 200 : 400
		);
	}

	/**
	 * Activate license key through Lemon Squeezy API.
	 *
	 * @param WP_REST_Request $request Full data about the request.
	 * @return \WP_REST_Response|\WP_Error
	 */
	public function activate_key( $request ) {
		$license_key   = $request->get_param( 'license_key' );
		$instance_name = $request->get_param( 'instance_name' );
		$is_valid      = false;
		$error_message = '';
		$api_key       = get_option( 'lsq_api_key' );

		if ( empty( $api_key ) ) {
			return new \WP_REST_Response(
				array(
					'success' => false,
					'error'   => __( 'Unauthorized request', 'lemon-squeezy' ),
				),
				401
			);
		}

		$response = wp_remote_post(
			LSQ_API_URL . "/v1/licenses/activate?license_key={$license_key}&instance_name={$instance_name}",
			array(
				'headers' => array(
					'Authorization' => 'Bearer ' . $api_key,
					'Accept'        => 'application/vnd.api+json',
					'Content-Type'  => 'application/vnd.api+json',
					'Cache-Control' => 'no-cache',
				),
			)
		);

		$body = json_decode( $response['body'], true );

		if ( ! is_wp_error( $response ) ) {
			if ( 200 === wp_remote_retrieve_response_code( $response ) ) {
				$is_valid = true;
			} else {
				$error_message = isset( $body['error'] ) ? $body['error'] : wp_remote_retrieve_response_message( $response );
			}
		} else {
			$error_message = $response->get_error_message();
		}

		return new \WP_REST_Response(
			array(
				'success' => $is_valid,
				'error'   => $error_message,
				'data'    => $body,
			),
			$is_valid ? 200 : 400
		);
	}

	/**
	 * Deactivate license key through Lemon Squeezy API.
	 *
	 * @param WP_REST_Request $request Full data about the request.
	 * @return \WP_REST_Response|\WP_Error
	 */
	public function deactivate_key( $request ) {
		$license_key   = $request->get_param( 'license_key' );
		$instance_name = $request->get_param( 'instance_id' );
		$is_valid      = false;
		$error_message = null;
		$api_key       = get_option( 'lsq_api_key' );

		if ( empty( $api_key ) ) {
			return new \WP_REST_Response(
				array(
					'success' => false,
					'error'   => __( 'Unauthorized request', 'lemon-squeezy' ),
				),
				401
			);
		}

		$response = wp_remote_post(
			LSQ_API_URL . "/v1/licenses/deactivate?license_key={$license_key}&instance_id={$instance_name}",
			array(
				'headers' => array(
					'Authorization' => 'Bearer ' . $api_key,
					'Accept'        => 'application/vnd.api+json',
					'Content-Type'  => 'application/vnd.api+json',
					'Cache-Control' => 'no-cache',
				),
			)
		);

		if ( ! is_wp_error( $response ) ) {
			$body = json_decode( $response['body'], true );
			if ( 200 === wp_remote_retrieve_response_code( $response ) ) {
				$is_valid = $body['deactivated'];
			} else {
				$error_message = isset( $body['error'] ) ? $body['error'] : wp_remote_retrieve_response_message( $response );
			}
		} else {
			$error_message = $response->get_error_message();
		}

		return new \WP_REST_Response(
			array(
				'success' => $is_valid,
				'error'   => $error_message,
			),
			$is_valid ? 200 : 400
		);
	}

	/**
	 * Get products from the Lemon Squeezy API.
	 *
	 * @param \WP_REST_Request $request Full data about the request.
	 * @return \WP_Error|\WP_REST_Response
	 */
	public function get_stores() {
		// Check LS API connection.
		$api_key       = get_option( 'lsq_api_key' );
		$error_message = '';

		if ( ! isset( $api_key ) || empty( $api_key ) ) {
			return new \WP_REST_Response(
				array(
					'success'    => false,
					'error'      => __( 'Unauthorized request', 'lemon-squeezy' ),
					'error_code' => 'unauthorized',
				),
				401
			);
		}

		// Get stores.
		$response = wp_remote_get(
			LSQ_API_URL . '/v1/stores/',
			array(
				'headers' => array(
					'Authorization' => 'Bearer ' . $api_key,
					'Accept'        => 'application/vnd.api+json',
					'Content-Type'  => 'application/vnd.api+json',
					'Cache-Control' => 'no-cache',
				),
			)
		);

		if ( ! is_wp_error( $response ) ) {
			if ( 200 === wp_remote_retrieve_response_code( $response ) ) {
				$store_data = json_decode( $response['body'] );
				$stores     = array();

				// Build product list.
				if ( isset( $store_data ) && ! empty( $store_data ) ) {
					foreach ( $store_data->data as $store ) {
						$stores[] = array(
							'label' => $store->attributes->name,
							'value' => $store->id,
						);
					}
				}

				return new \WP_REST_Response(
					array(
						'success' => true,
						'stores'  => $stores,
					),
					200
				);
			} else {
				$error_message = wp_remote_retrieve_response_message( $response );
			}
		} else {
			$error_message = $response->get_error_message();
		}

		return new \WP_REST_Response(
			array(
				'success'    => false,
				'error'      => $error_message,
				'error_code' => 'api_error',
			),
			400
		);
	}

	/**
	 * Get products from the Lemon Squeezy API.
	 *
	 * @param \WP_REST_Request $request Full data about the request.
	 * @return \WP_Error|\WP_REST_Response
	 */
	public function get_products( $request ) {
		// Check LS API connection.
		$api_key       = get_option( 'lsq_api_key' );
		$error_message = '';

		if ( ! isset( $api_key ) || empty( $api_key ) ) {
			return new \WP_REST_Response(
				array(
					'success'    => false,
					'error'      => __( 'Unauthorized request', 'lemon-squeezy' ),
					'error_code' => 'unauthorized',
				),
				401
			);
		}

		$store_id  = filter_var( $request->get_param( 'store_id' ), FILTER_SANITIZE_FULL_SPECIAL_CHARS );
		$page_size = rawurlencode( 'page[size]' );

		$response = wp_remote_get(
			LSQ_API_URL . "/v1/stores/{$store_id}/products?" . $page_size . '=100',
			array(
				'headers' => array(
					'Authorization' => 'Bearer ' . $api_key,
					'Accept'        => 'application/vnd.api+json',
					'Content-Type'  => 'application/vnd.api+json',
					'Cache-Control' => 'no-cache',
				),
			)
		);

		if ( ! is_wp_error( $response ) ) {
			if ( 200 === wp_remote_retrieve_response_code( $response ) ) {
				$product_data = json_decode( $response['body'] );
				$products     = array();

				foreach ( $product_data->data as $product ) {
					if ( 'published' !== $product->attributes->status ) {
						continue;
					}

					$products[] = array(
						'label' => $product->attributes->name,
						'value' => $product->attributes->buy_now_url,
					);
				}

				return new \WP_REST_Response(
					array(
						'success'  => true,
						'products' => $products,
					),
					200
				);
			} else {
				$error_message = wp_remote_retrieve_response_message( $response );
			}
		} else {
			$error_message = $response->get_error_message();
		}

		return new \WP_REST_Response(
			array(
				'success'    => false,
				'error'      => $error_message,
				'error_code' => 'api_error',
			),
			400
		);
	}

	/**
	 * Validate and return a software update from the Lemon Squeezy API.
	 *
	 * @param \WP_REST_Request $request Full data about the request.
	 * @return \WP_Error|\WP_REST_Response
	 */
	public function get_update( $request ) {
		$api_key = get_option( 'lsq_api_key' );

		if ( empty( $api_key ) ) {
			return new \WP_REST_Response(
				array(
					'success'    => false,
					'error'      => __( 'Unauthorized request', 'lemon-squeezy' ),
					'error_code' => 'unauthorized',
				),
				401
			);
		}

		$license_key = filter_var( $request->get_param( 'license_key' ), FILTER_SANITIZE_FULL_SPECIAL_CHARS );
		if ( empty( $license_key ) ) {
			return new \WP_REST_Response(
				array(
					'success'    => false,
					'error'      => __( 'Missing license_key', 'lemon-squeezy' ),
					'error_code' => 'missing_license_key',
				),
				401
			);
		}

		$lsq_updater = new LSQ_Updater();

		$license = $lsq_updater->get_license( $license_key );
		if ( empty( $license->valid ) || empty( $license->license_key->id ) ) {
			return new \WP_REST_Response(
				array(
					'success'    => false,
					'error'      => __( 'Invalid license_key', 'lemon-squeezy' ),
					'error_code' => 'invalid_license_key',
				),
				401
			);
		}

		$license_key_obj = $lsq_updater->get_license_key( $license->license_key->id );
		if ( empty( $license_key_obj ) || empty( $license_key_obj->data->relationships->{'order-item'}->data ) ) {
			return new \WP_REST_Response(
				array(
					'success'    => false,
					'error'      => __( 'Error fetching license_key', 'lemon-squeezy' ),
					'error_code' => 'error_fetching_license_key',
				),
				400
			);
		}

		$order_item = $lsq_updater->relation_from_license_key( $license_key_obj, 'order-item' );
		if ( ! $order_item ) {
			return new \WP_REST_Response(
				array(
					'success'    => false,
					'error'      => __( 'Invalid order item', 'lemon-squeezy' ),
					'error_code' => 'invalid_order_item',
				),
				400
			);
		}

		$files = $lsq_updater->get_files( $order_item->attributes->variant_id );
		if ( empty( $files->data ) ) {
			return new \WP_REST_Response(
				array(
					'success'    => false,
					'error'      => __( 'Missing files', 'lemon-squeezy' ),
					'error_code' => 'missing_files',
				),
				400
			);
		}

		$sorted_files = $lsq_updater->sort_files_by_version( $files->data );
		$latest_file  = array_pop( $sorted_files );
		if ( empty( $latest_file->attributes->version ) ) {
			return new \WP_REST_Response(
				array(
					'success'    => false,
					'error'      => __( 'Missing file version', 'lemon-squeezy' ),
					'error_code' => 'missing_file_version',
				),
				400
			);
		}

		$store   = $lsq_updater->relation_from_license_key( $license_key_obj, 'store' );
		$product = $lsq_updater->relation_from_license_key( $license_key_obj, 'product' );

		return new \WP_REST_Response(
			array(
				'success'    => true,
				'error'      => '',
				'error_code' => '',
				'update'     => array(
					'version'        => $latest_file->attributes->version,
					'tested'         => null,
					'requires'       => null,
					'author'         => $store ? $store->attributes->name : null,
					'author_profile' => $store ? $store->attributes->url : null,
					'download_link'  => $latest_file->attributes->download_url,
					'trunk'          => $latest_file->attributes->download_url,
					'requires_php'   => null,
					'last_updated'   => null,
					'sections'       => array(
						'description' => $product ? $product->attributes->description : null,
						'changelog'   => $latest_file->attributes->version,
					),
				),
			),
			200
		);
	}
}
