<?php
/**
 * Adds domain mapping and auto SSL support to customer hosting networks on ServerPilot.
 *
 * @package WP_Ultimo
 * @subpackage Integrations/Host_Providers/ServerPilot_Host_Provider
 * @since 2.0.0
 */

namespace WP_Ultimo\Integrations\Host_Providers;

use Psr\Log\LogLevel;
use WP_Ultimo\Integrations\Host_Providers\Base_Host_Provider;

// Exit if accessed directly
defined('ABSPATH') || exit;

/**
 * This base class should be extended to implement new host integrations for SSL and domains.
 */
class ServerPilot_Host_Provider extends Base_Host_Provider {

	use \WP_Ultimo\Traits\Singleton;

	/**
	 * Keeps the title of the integration.
	 *
	 * @var string
	 * @since 2.0.0
	 */
	protected $id = 'serverpilot';

	/**
	 * Keeps the title of the integration.
	 *
	 * @var string
	 * @since 2.0.0
	 */
	protected $title = 'ServerPilot';

	/**
	 * Link to the tutorial teaching how to make this integration work.
	 *
	 * @var string
	 * @since 2.0.0
	 */
	protected $tutorial_link = 'https://help.wpultimo.com/en/articles/2632349-configuring-automatic-domain-syncing-with-serverpilot-io-with-autossl-support';

	/**
	 * Array containing the features this integration supports.
	 *
	 * @var array
	 * @since 2.0.0
	 */
	protected $supports = [
		'autossl',
	];

	/**
	 * Constants that need to be present on wp-config.php for this integration to work.
	 *
	 * @since 2.0.0
	 * @var array
	 */
	protected $constants = [
		'WU_SERVER_PILOT_CLIENT_ID',
		'WU_SERVER_PILOT_API_KEY',
		'WU_SERVER_PILOT_APP_ID',
	];

	/**
	 * Picks up on tips that a given host provider is being used.
	 *
	 * We use this to suggest that the user should activate an integration module.
	 *
	 * @since 2.0.0
	 * @return boolean
	 */
	public function detect() {

		return defined('WP_PLUGIN_DIR') && preg_match('/\/srv\/users\/(.+)\/apps\/(.+)/', (string) WP_PLUGIN_DIR);
	}

	/**
	 * Returns the list of installation fields.
	 *
	 * @since 2.1.2
	 * @return array
	 */
	public function get_fields() {

		return [
			'WU_SERVER_PILOT_CLIENT_ID' => [
				'title'       => __('ServerPilot Client ID', 'wp-ultimo'),
				'desc'        => __('Your ServerPilot Client ID.', 'wp-ultimo'),
				'placeholder' => __('e.g. cid_lSmjevkdoSOpasYVqm', 'wp-ultimo'),
			],
			'WU_SERVER_PILOT_API_KEY'   => [
				'title'       => __('ServerPilot API Key', 'wp-ultimo'),
				'desc'        => __('The API Key retrieved in the previous step.', 'wp-ultimo'),
				'placeholder' => __('e.g. eYP0Jo3Fzzm5SOZCi5nLR0Mki2lbYZ', 'wp-ultimo'),
			],
			'WU_SERVER_PILOT_APP_ID'    => [
				'title'       => __('ServerPilot App ID', 'wp-ultimo'),
				'desc'        => __('The App ID retrieved in the previous step.', 'wp-ultimo'),
				'placeholder' => __('e.g. 940288', 'wp-ultimo'),
			],
		];
	}

	/**
	 * This method gets called when a new domain is mapped.
	 *
	 * @since 2.0.0
	 * @param string $domain The domain name being mapped.
	 * @param int    $site_id ID of the site that is receiving that mapping.
	 * @return void
	 */
	public function on_add_domain($domain, $site_id): void {

		$current_domain_list = $this->get_server_pilot_domains();

		if ($current_domain_list && is_array($current_domain_list)) {
			$this->send_server_pilot_api_request(
				'',
				[
					'domains' => array_merge($current_domain_list, [$domain, 'www.' . $domain]),
				]
			);

			/**
			 * Makes sure autoSSL is always on
			 */
			$this->turn_server_pilot_auto_ssl_on();
		}
	}

	/**
	 * This method gets called when a mapped domain is removed.
	 *
	 * @since 2.0.0
	 * @param string $domain The domain name being removed.
	 * @param int    $site_id ID of the site that is receiving that mapping.
	 * @return void
	 */
	public function on_remove_domain($domain, $site_id): void {

		$current_domain_list = $this->get_server_pilot_domains();

		if ($current_domain_list && is_array($current_domain_list)) {

			/**
			 * Removes the current domain fromt he domain list
			 */
			$current_domain_list = array_filter($current_domain_list, fn($remote_domain) => $remote_domain !== $domain && 'www.' . $domain !== $remote_domain);

			$this->send_server_pilot_api_request(
				'',
				[
					'domains' => $current_domain_list,
				]
			);
		}
	}

	/**
	 * This method gets called when a new subdomain is being added.
	 *
	 * This happens every time a new site is added to a network running on subdomain mode.
	 *
	 * @since 2.0.0
	 * @param string $subdomain The subdomain being added to the network.
	 * @param int    $site_id ID of the site that is receiving that mapping.
	 * @return void
	 */
	public function on_add_subdomain($subdomain, $site_id): void {

		$current_domain_list = $this->get_server_pilot_domains();

		if ($current_domain_list && is_array($current_domain_list)) {
			$this->send_server_pilot_api_request(
				'',
				[
					'domains' => array_merge($current_domain_list, [$subdomain]),
				]
			);

			/**
			 * Makes sure autoSSL is always on
			 */
			$this->turn_server_pilot_auto_ssl_on();
		}
	}

	/**
	 * This method gets called when a new subdomain is being removed.
	 *
	 * This happens every time a new site is removed to a network running on subdomain mode.
	 *
	 * @since 2.0.0
	 * @param string $subdomain The subdomain being removed to the network.
	 * @param int    $site_id ID of the site that is receiving that mapping.
	 * @return void
	 */
	public function on_remove_subdomain($subdomain, $site_id) {}

	/**
	 * Sends a request to ServerPilot, with the right API key.
	 *
	 * @since  1.7.3
	 * @param  string $endpoint Endpoint to send the call to.
	 * @param  array  $data     Array containing the params to the call.
	 * @param  string $method   HTTP Method: POST, GET, PUT, etc.
	 * @return object
	 */
	public function send_server_pilot_api_request($endpoint, $data = [], $method = 'POST') {

		$post_fields = [
			'timeout'  => 45,
			'blocking' => true,
			'method'   => $method,
			'body'     => $data ? json_encode($data) : [],
			'headers'  => [
				'Authorization' => 'Basic ' . base64_encode(WU_SERVER_PILOT_CLIENT_ID . ':' . WU_SERVER_PILOT_API_KEY),
				'Content-Type'  => 'application/json',
			],
		];

		$response = wp_remote_request('https://api.serverpilot.io/v1/apps/' . WU_SERVER_PILOT_APP_ID . $endpoint, $post_fields);

		if ( ! is_wp_error($response)) {
			$body = json_decode(wp_remote_retrieve_body($response), true);

			if (json_last_error() === JSON_ERROR_NONE) {
				return $body;
			}
		}

		return $response;
	}

	/**
	 * Makes sure ServerPilot autoSSL is always on, when possible.
	 *
	 * @since 1.7.4
	 * @return bool
	 */
	public function turn_server_pilot_auto_ssl_on() {

		return $this->send_server_pilot_api_request(
			'/ssl',
			[
				'auto' => true,
			]
		);
	}

	/**
	 * Get the current list of domains added on Server Pilot.
	 *
	 * @since 1.7.4
	 * @return mixed
	 */
	public function get_server_pilot_domains() {

		$app_info = $this->send_server_pilot_api_request('', [], 'GET');

		if (isset($app_info['data']['domains'])) {
			return $app_info['data']['domains'];
		}

		/*
		 * Log response so we can see what went wrong
		 */

		// translators: %s is the json_encode of the error.
		wu_log_add('integration-serverpilot', sprintf(__('An error occurred while trying to get the current list of domains: %s', 'wp-ultimo'), json_encode($app_info)), LogLevel::ERROR);

		return false;
	}

	/**
	 * Tests the connection with the ServerPilot API.
	 *
	 * @since 2.0.0
	 * @return void
	 */
	public function test_connection(): void {

		$response = $this->send_server_pilot_api_request('', [], 'GET');

		if (is_wp_error($response) || wu_get_isset($response, 'error')) {
			wp_send_json_error($response);
		}

		wp_send_json_success($response);
	}

	/**
	 * Renders the instructions content.
	 *
	 * @since 2.1.2
	 * @return void
	 */
	public function get_instructions(): void {

		wu_get_template('wizards/host-integrations/serverpilot-instructions');
	}

	/**
	 * Returns the description of this integration.
	 *
	 * @since 2.0.0
	 * @return string
	 */
	public function get_description() {

		return __('ServerPilot is a cloud service for hosting WordPress and other PHP websites on servers at DigitalOcean, Amazon, Google, or any other server provider. You can think of ServerPilot as a modern, centralized hosting control panel.', 'wp-ultimo');
	}

	/**
	 * Returns the logo for the integration.
	 *
	 * @since 2.1.2
	 * @return string
	 */
	public function get_logo() {

		return wu_get_asset('serverpilot.svg', 'img/hosts');
	}
}