<?php
namespace Fabrica\Dashboard;

if (!defined('WPINC')) { die(); }

abstract class BaseCommon {

	// Data cached for use by other classes
	public static $textDomain;
	public static $pluginVersion;
	public static $dbPrefix;
	public static $dbBasePrefix;
	public static $postTypes;
	public static $frontendPostTypes; /* post types which have public URLs (publicly_queryable) */
	public static $taxonomies;
	public static $frontendTaxonomies; /* taxonomies which have public URLs (publicly_queryable) */
	public static $postStatuses;
	public static $currentUser;
	public static $settings;
	public static $activationPageSlug;
	public static $isEditor = false;
	public static $isModerator = false;
	public static $hasComments = false;
	public static $lastLogin = false;
	public static $currentLogin = false;
	public static $totalUsers = 1;

	public static function init() {
		add_action('admin_init', array(Base::class, 'cacheData'));
		add_action('admin_enqueue_scripts', array(Base::class, 'loadAssets'));
		add_action('wp_dashboard_setup', array(Base::class, 'removeDefaultWidgets'));
		add_filter('admin_title', array(Base::class, 'changeTitle'), 10, 2);
		add_filter('esc_html', array(Base::class, 'updateTitleHeader'), 10, 2);
		add_filter('gettext', array(Base::class, 'translateText'), 10, 3);
	}

	/*
	// Public functions respond to WP hooks to perform basic config and cache data
	*/

	public static function cacheData() {
		global $wpdb;

		// Plugin credentials
		$pluginData = get_plugin_data(Plugin::$mainFile);
		self::$textDomain = $pluginData['TextDomain'];
		self::$pluginVersion = $pluginData['Version'];

		// Table prefix in database
		self::$dbPrefix = $wpdb->prefix;
		self::$dbBasePrefix = $wpdb->base_prefix;

		// Post Types
		$types = get_post_types(array('public' => true), 'objects');
		foreach ($types as $type) {

			// Only include post types with at least one entry
			$query = $wpdb->prepare('SELECT COUNT(*) as count FROM ' . self::$dbPrefix . 'posts WHERE post_type = %s AND post_status IN (\'publish\', \'future\', \'draft\', \'trash\')', $type->name);
			$count = $wpdb->get_results($query, OBJECT_K);
			if (key($count) == 0) {
				continue;
			}

			// Compile array
			self::$postTypes[$type->name] = array(
				'plural' => $type->label,
				'singular' => $type->labels->singular_name
			);
			if ($type->publicly_queryable || $type->name == 'page') {
				self::$frontendPostTypes[$type->name] = array(
					'plural' => $type->label,
					'singular' => $type->labels->singular_name
				);
			}
		}

		// Add Synced Patterns if they exist
		$blocksType = get_post_type_object('wp_block');
		if (!empty($blocksType)) {
			self::$postTypes[$blocksType->name] = array(
				'plural' => __('Synced Patterns', self::$textDomain),
				'singular' => __('Synced Pattern', self::$textDomain)
			);
		}

		// Taxonomies
		$taxes = get_taxonomies(array('public' => true), 'objects');
		foreach ($taxes as $tax) {
			self::$taxonomies[$tax->name] = array(
				'plural' => $tax->label,
				'singular' => $tax->labels->singular_name
			);
			if ($tax->publicly_queryable) {
				self::$frontendTaxonomies[$tax->name] = array(
					'plural' => $tax->label,
					'singular' => $tax->labels->singular_name
				);
			}
		}

		// Statuses (mainly for the internationalized labels)
		$statuses = get_post_stati(array(), 'objects');
		self::$postStatuses = array(
			'publish' => $statuses['publish']->label,
			'future' => $statuses['future']->label,
			'draft' => $statuses['draft']->label,
			'trash' => $statuses['trash']->label
		);

		// Plugin's own options
		self::$settings = get_option('fd-settings') ?: array();

		// Check if site has at least one genuine comment
		$query = 'SELECT COUNT(*) FROM ' . self::$dbPrefix . 'comments WHERE comment_type = \'comment\' AND comment_ID != 1 AND comment_author != \'A WordPress Commenter\'';
		$results = $wpdb->get_results($query, OBJECT_K);
		if (key($results) > 0) {
			self::$hasComments = true;
		}

		// Current user + key privileges
		self::$currentUser = wp_get_current_user();
		$lastLogin = get_user_meta(self::$currentUser->ID, '_fd_last_login', true);
		if ($lastLogin) {
			self::$lastLogin = $lastLogin;
		}
		$currentLogin = get_user_meta(self::$currentUser->ID, '_fd_current_login', true);
		if ($currentLogin) {
			self::$currentLogin = $currentLogin;
		}
		if (current_user_can('edit_others_pages')) {
			self::$isEditor = true;
		}
		if (current_user_can('moderate_comments')) {
			self::$isModerator = true;
		}

		// All users
		$userstable = Base::$dbBasePrefix . 'users';
		$usermetatable = Base::$dbBasePrefix . 'usermeta';
		$query = $wpdb->prepare("SELECT COUNT(*) FROM {$userstable} INNER JOIN {$usermetatable} ON ({$userstable}.ID = {$usermetatable}.user_id) WHERE {$usermetatable}.meta_key = %s", self::$dbPrefix . 'capabilities');
		$results = $wpdb->get_results($query, OBJECT_K);
		if ($results) {
			self::$totalUsers = key($results);
		}
	}

	// Add custom CSS
	public static function loadAssets() {
		$pluginUrl = plugin_dir_url(Plugin::$mainFile);
		$pluginPath = plugin_dir_path(Plugin::$mainFile);
		wp_enqueue_style('fd-css', $pluginUrl . 'css/main.css', false, filemtime($pluginPath . 'css/main.css'));
		wp_enqueue_script('fd-js', $pluginUrl . 'js/main.js', array('jquery'), filemtime($pluginPath . 'js/main.js'), true);
		wp_localize_script('fd-js', 'fdAjax', array('url' => admin_url('admin-ajax.php')));
	}

	// Remove WP default widgets
	public static function removeDefaultWidgets() {
		if (array_key_exists('enable_default_boxes', self::$settings) && self::$settings['enable_default_boxes'] === '1') {
			return;
		}
		remove_action('welcome_panel', 'wp_welcome_panel'); // Welcome
		remove_meta_box('dashboard_right_now', 'dashboard', 'normal'); // At a Glance
		remove_meta_box('dashboard_recent_comments', 'dashboard', 'normal'); // Recent Comments
		remove_meta_box('dashboard_activity', 'dashboard', 'normal'); // Activity
		remove_meta_box('dashboard_quick_press', 'dashboard', 'side'); // Quick Press
		remove_meta_box('dashboard_recent_drafts', 'dashboard', 'side'); // Recent Drafts
		remove_meta_box('dashboard_primary', 'dashboard', 'side'); // WordPress.com Blog
		remove_meta_box('dashboard_secondary', 'dashboard', 'side'); // Other WordPress News
		remove_meta_box('dashboard_incoming_links','dashboard', 'normal'); // Incoming Links
		remove_meta_box('dashboard_plugins', 'dashboard', 'normal'); // Plugins
	}

	/*
	// Static functions offer utilities throughout the plugin
	*/

	// Text-rendering shortcut that prints an m-dash instead of 0
	public static function z2d($var) {
		return $var > 0 ? $var : '-';
	}

	// Renders file size in human-readable/relevant format
	public static function formatSize($size) {
		$units = array('B', 'KB', 'MB', 'GB', 'TB', 'PB', 'EB', 'ZB', 'YB');
		$power = $size > 0 ? floor(log($size, 1024)) : 0;
		return number_format($size / pow(1024, $power), 1, '.', ',') . ' ' . $units[$power];
	}

	// Renders time elapsed as human readable abbreviation
	public static function ago($from, $to = '') {
		if (empty($to)) {
			$to = time();
		}
		$diff = (int) abs($to - $from);
		if ($diff < HOUR_IN_SECONDS) {
			$mins = round($diff / MINUTE_IN_SECONDS);
			if ($mins <= 1) { $mins = 1; }
			// translators: 1: minutes elapsed
			$since = sprintf(_x("%sm", "time elapsed in minutes", Base::$textDomain), $mins);
		} else if ($diff < DAY_IN_SECONDS && $diff >= HOUR_IN_SECONDS) {
			$hours = round($diff / HOUR_IN_SECONDS);
			if ($hours <= 1) { $hours = 1; }
			// translators: 1: hours elapsed
			$since = sprintf(_x("%sh", "time elapsed in hours", Base::$textDomain), $hours);
		} else if ($diff < WEEK_IN_SECONDS && $diff >= DAY_IN_SECONDS) {
			$days = round($diff / DAY_IN_SECONDS);
			if ($days <= 1) { $days = 1; }
			// translators: 1: days elapsed
			$since = sprintf(_x("%sd", "time elapsed in days", Base::$textDomain), $days);
		} else if ($diff < YEAR_IN_SECONDS && $diff >= WEEK_IN_SECONDS) {
			$weeks = round($diff / WEEK_IN_SECONDS);
			if ($weeks <= 1) { $weeks = 1; }
			// translators: 1: weeks elapsed
			$since = sprintf(_x("%sw", "time elapsed in weeks", Base::$textDomain), $weeks);
		} else if ($diff >= YEAR_IN_SECONDS) {
			$years = round($diff / YEAR_IN_SECONDS);
			if ($years <= 1) { $years = 1; }
			// translators: 1: years elapsed
			$since = sprintf(_x("%sy", "time elapsed in years", Base::$textDomain), $years);
		}

		// Add longform version as tooltip
		return '<span title="' . human_time_diff($from, $to) . ' ago">' . $since . '</span>';
	}

	// Renders 2-column table of statistics (used by both Overview boxes)
	public static function renderStatsTable($stats) {
		if (!$stats || count($stats) == 0) {
			return;
		}
		?><tr><?php
			$c = 0;
			foreach ($stats as $stat) {
				if ($c > 0 && $c % 2 == 0) echo '</tr></tr>';
				?><td><?php
					if (array_key_exists('trafficlight', $stat)) {
						?><span class="fd-trafficlight fd-trafficlight--<?php echo esc_attr($stat['trafficlight']); ?>"></span> <?php
					} else if (array_key_exists('dashicon', $stat)) {
						?><span class="fd-grey dashicons dashicons-<?php echo esc_attr($stat['dashicon']); ?>"></span> <?php
					}
					echo esc_html($stat['label']); ?>
				</td>
				<td class="fd-util-right<?php if ($c % 2 == 0 && count($stats) > 1) echo ' fd-util-border-right"'; ?>"><?php echo esc_html($stat['number']); ?></td><?php
				$c++;
			}
			if ($c % 2 == 1 && count($stats) > 1) echo '<td></td><td></td>'; // Fill in missing cells if odd number of stats
		?></tr><?php
	}

	// Change Dashboard title so it can be identified individually when filtering `esc_html`
	public static function changeTitle($adminTitle, $title) {
		if (get_current_screen()->base == 'dashboard') {
			$GLOBALS['title'] = '{%Fabrica Dashboard%}';
		}
		return $adminTitle;
	}

	// Add relevant links to Dashboard header
	public static function updateTitleHeader($safeText, $text) {
		if ($text !== '{%Fabrica Dashboard%}') { return $safeText; }
		return static::getPageTitle();
	}

	// `true` if current WP version support [un]synced patterns, `false` if it uses reusable blocks instead
	private static function supportsPattern() {
		return version_compare(get_bloginfo('version'), '6.3', '>=');
	}

	public static function translateText($translation, $text, $domain) {
		if ($domain != self::$textDomain) { return $translation; }
		if (self::supportsPattern()) { return $translation; }
		if ($text == 'Synced Patterns') {
			return __('Reusable Blocks', self::$textDomain);
		} else if ($text == 'Synced Pattern') {
			return __('Reusable Block', self::$textDomain);
		}
		return $translation;
	}

	// Render page title: abstract function to be implemented by licensed and non-licensed `Base` implementations
	public abstract static function getPageTitle();
}
