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

namespace WP_Ultimo\Integrations\Host_Providers;

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

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

/**
 * This base class should be extended to implement new host integrations for SSL and domains.
 */
class CPanel_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 = 'cpanel';

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

	/**
	 * Link to the tutorial teaching how to make this integration work.
	 *
	 * @var string
	 * @since 2.0.0
	 */
	protected $tutorial_link = 'https://help.wpultimo.com/article/295-configuring-automatic-domain-syncing-with-cpanel';

	/**
	 * Array containing the features this integration supports.
	 *
	 * @var array
	 * @since 2.0.0
	 */
	protected $supports = array(
		'autossl',
		'no-instructions',
	);

	/**
	 * Constants that need to be present on wp-config.php for this integration to work.
	 *
	 * @since 2.0.0
	 * @var array
	 */
	protected $constants = array(
		'WU_CPANEL_USERNAME',
		'WU_CPANEL_PASSWORD',
		'WU_CPANEL_HOST',
	);

	/**
	 * Constants that are optional on wp-config.php.
	 *
	 * @since 2.0.0
	 * @var array
	 */
	protected $optional_constants = array(
		'WU_CPANEL_PORT',
		'WU_CPANEL_ROOT_DIR'
	);

	/**
	 * Holds the API object.
	 *
	 * @since 2.0.0
	 * @var WP_Ultimo\Integrations\Host_Providers\CPanel_API\CPanel_API
	 */
	protected $api = null;

	/**
     * 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.
     * Unfortunately, we don't have a good method of detecting if someone is running from cPanel.
     *
     * @since 2.0.0
     */
	public function detect(): bool {

		return false;

	} // end detect;

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

		return array(
			'WU_CPANEL_USERNAME' => array(
				'title'       => __('cPanel Username', 'wp-ultimo'),
				'placeholder' => __('e.g. username', 'wp-ultimo'),
			),
			'WU_CPANEL_PASSWORD' => array(
				'type'        => 'password',
				'title'       => __('cPanel Password', 'wp-ultimo'),
				'placeholder' => __('password', 'wp-ultimo'),
			),
			'WU_CPANEL_HOST'     => array(
				'title'       => __('cPanel Host', 'wp-ultimo'),
				'placeholder' => __('e.g. yourdomain.com', 'wp-ultimo'),
			),
			'WU_CPANEL_PORT'     => array(
				'title'       => __('cPanel Port', 'wp-ultimo'),
				'placeholder' => __('Defaults to 2083', 'wp-ultimo'),
				'value'       => 2083,
			),
			'WU_CPANEL_ROOT_DIR' => array(
				'title'       => __('Root Directory', 'wp-ultimo'),
				'placeholder' => __('Defaults to /public_html', 'wp-ultimo'),
				'value'       => '/public_html',
			),
		);

	} // end get_fields;

	/**
	 * 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) {

		// Root Directory
		$root_dir = defined('WU_CPANEL_ROOT_DIR') && WU_CPANEL_ROOT_DIR ? WU_CPANEL_ROOT_DIR : '/public_html';

		// Send Request
		$results = $this->load_api()->api2('AddonDomain', 'addaddondomain', array(
			'dir'       => $root_dir,
			'newdomain' => $domain,
			'subdomain' => $this->get_subdomain($domain),
		));

		$this->log_calls($results);

	} // end on_add_domain;

	/**
	 * 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) {

		// Send Request
		$results = $this->load_api()->api2('AddonDomain', 'deladdondomain', array(
			'domain'    => $domain,
			'subdomain' => $this->get_subdomain($domain) . '_' . $this->get_site_url(),
		));

		$this->log_calls($results);

	} // end on_remove_domain;

	/**
	 * 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) {

		// Root Directory
		$root_dir = defined('WU_CPANEL_ROOT_DIR') && WU_CPANEL_ROOT_DIR ? WU_CPANEL_ROOT_DIR : '/public_html';

		$subdomain = $this->get_subdomain($subdomain, false);

		$rootdomain = str_replace($subdomain . '.', '', $this->get_site_url($site_id));

		// Send Request
		$results = $this->load_api()->api2('SubDomain', 'addsubdomain', array(
			'dir'        => $root_dir,
			'domain'     => $subdomain,
			'rootdomain' => $rootdomain,
		));

		// Check the results
		$this->log_calls($results);

	} // end on_add_subdomain;

	/**
	 * 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) {} // end on_remove_subdomain;

	/**
	 * Load the CPanel API.
	 *
	 * @since 2.0.0
	 * @return WU_CPanel
	 */
	public function load_api() {

		if ($this->api === null) {

			$username = defined('WU_CPANEL_USERNAME') ? WU_CPANEL_USERNAME : '';
			$password = defined('WU_CPANEL_PASSWORD') ? WU_CPANEL_PASSWORD : '';
			$host     = defined('WU_CPANEL_HOST') ? WU_CPANEL_HOST : '';
			$port     = defined('WU_CPANEL_PORT') && WU_CPANEL_PORT ? WU_CPANEL_PORT : 2083;

			/*
			 * Set up the API.
			 */
			$this->api = new CPanel_API($username, $password, preg_replace('#^https?://#', '', (string) $host), $port);

		} // end if;

		return $this->api;

	} // end load_api;
	/**
	 * Returns the Site URL.
	 *
	 * @since  1.6.2
	 * @param null|int $site_id The site id.
	 */
	public function get_site_url($site_id = null): string {

		return trim(preg_replace('#^https?://#', '', get_site_url($site_id)), '/');

	} // end get_site_url;

	/**
	 * Returns the sub-domain version of the domain.
	 *
	 * @since 1.6.2
	 * @param string $domain The domain to be used.
	 * @param string $mapped_domain If this is a mapped domain.
	 * @return string
	 */
	public function get_subdomain($domain, $mapped_domain = true) {

		if ($mapped_domain === false) {

			$domain_parts = explode('.', $domain);

			return array_shift($domain_parts);

		} // end if;

		$subdomain = str_replace(array('.', '/'), '', $domain);

		return $subdomain;

	} // end get_subdomain;

	/**
	 * Logs the results of the calls for debugging purposes
	 *
	 * @since 1.6.2
	 * @param object $results Results of the cPanel call.
	 * @return bool
	 */
	public function log_calls($results) {

		if (is_object($results->cpanelresult->data)) {

			return wu_log_add('integration-cpanel', $results->cpanelresult->data->reason);

		} elseif (!isset($results->cpanelresult->data[0])) {

			return wu_log_add('integration-cpanel', __('Unexpected error ocurred trying to sync domains with CPanel', 'wp-ultimo'), LogLevel::ERROR);

		} // end if;

		return wu_log_add('integration-cpanel', $results->cpanelresult->data[0]->reason);

	} // end log_calls;

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

		return __('cPanel is the management panel being used on a large number of shared and dedicated hosts across the globe.', 'wp-ultimo');

	} // end get_description;

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

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

	} // end get_logo;

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

		$results = $this->load_api()->api2('Cron', 'fetchcron', array());

		$this->log_calls($results);

		if (isset($results->cpanelresult->data) && !isset($results->cpanelresult->error)) {

			wp_send_json_success($results);

			exit;

		} // end if;

		wp_send_json_error($results);

	} // end test_connection;

	/**
	 * Returns the explainer lines for the integration.
	 *
	 * @since 2.0.0
	 * @return array
	 */
	public function get_explainer_lines() {

		$explainer_lines = array(
			'will'     => array(
				'send_domains' => __('Add a new Addon Domain on cPanel whenever a new domain mapping gets created on your network', 'wp-ultimo'),
			),
			'will_not' => array(),
		);

		if (is_subdomain_install()) {

			$explainer_lines['will']['send_sub_domains'] = __('Add a new SubDomain on cPanel whenever a new site gets created on your network', 'wp-ultimo');

		} // end if;

		return $explainer_lines;

	} // end get_explainer_lines;

} // end class CPanel_Host_Provider;
