<?php

namespace WPD_Platform\Services;

use WPD_Platform\Plugin;
use WPD_Platform\Singleton;
use WPD_Platform\Factories\ExternalHost;

/**
 * StatsService class
 *
 * Manages the statistics service and related operations
 *
 * @package WPD_Platform\Services
 */
class StatsService extends Singleton
{

	/**
	 * Fetch overall statistics for the platform.
	 *
	 * @param bool $full Whether to fetch full details or not.
	 * @return array An array of platform statistics.
	 */
	public function get($full = false)
	{
		$path = preg_replace('/\/wp-content.*$/', '', __DIR__);
		if (!defined('PLATFORM_WORDPRESS_DIR')) {
			define('PLATFORM_WORDPRESS_DIR', $path);
		}

		$response = [
			'secret' => Plugin::instance()->get_host()->get_secret(),
			'token'  => Plugin::instance()->get_host()->is_type_internal() ? S5_APP_TOKEN : Plugin::instance()->get_host()->get_token(),
			'php'    => PHP_VERSION,
			'size'   => $this->folderSize(PLATFORM_WORDPRESS_DIR),
			'cache'  => $this->getCacheDetails(),
			'site'   => $this->getSiteDetails($full),
			'logs' => $this->getLogs(),
			'error_logs' => $this->getErrorLogs(),
			'cookies' => $this->get_auth_cookies(),
		];

		if (Plugin::instance()->get_host()->is_type_external()) {
			$response['host_information'] = Plugin::instance()->get_host()->get_host_details();
		}

		return $response;
	}

	/**
	 * Calculate the size of a given directory.
	 *
	 * @param string $dir The directory path.
	 * @return int The size of the directory in bytes.
	 */
	public function folderSize($dir)
	{
		$size  = 0;
		$paths = glob(rtrim($dir, '/') . '/*', GLOB_NOSORT);

		if ($paths !== false) {
			foreach ($paths as $each) {
				$size += is_file($each) ? filesize($each) : $this->folderSize($each);
			}
		}

		return $size;
	}

	/**
	 * Get details about the cache configuration.
	 *
	 * @return array An array containing cache details.
	 */
	private function getCacheDetails()
	{
		return [
			'method'       => $this->getDbOption('platform_caching_method'),
			'op_cache'     => ini_get('opcache.enable'),
			'object_cache' => file_exists(PLATFORM_WORDPRESS_DIR . '/wp-content/object-cache.php'),
		];
	}

	/**
	 * Fetch a specific option value from the database.
	 *
	 * @param string $optionName The name of the option to fetch.
	 * @return mixed The option value, or null if not found.
	 */
	private function getDbOption($optionName)
	{
		global $wpdb;

		if (null === $wpdb) {
			// Log an error or throw an Exception.
			return null;
		}

		$result = $wpdb->get_row($wpdb->prepare("SELECT option_value FROM $wpdb->options WHERE option_name = %s LIMIT 1", $optionName));
		return $result->option_value ?? null;
	}

	/**
	 * Get details of the administrator user.
	 *
	 * @return array An array containing admin user details.
	 */
	private function getAdminUserDetails()
	{
		return $this->getUserDetails('administrator');
	}

	/**
	 * Get details of the editor user.
	 *
	 * @return array An array containing editor user details.
	 */
	private function getEditorUserDetails()
	{
		return $this->getUserDetails('editor');
	}

	/**
	 * Get details of users based on their role. Only use when client manager is enabled.
	 *
	 * @param string $role The role of the user.
	 * @return array An array containing user details.
	 */
	private function getUserDetails($role)
	{
		$users = get_users(
			[
				'role'   => $role,
				'orderby' => 'ID',
				'order' => 'ASC',
				'number' => 1,
			]
		);

		if (!empty($users)) {
			return [
				'username' => $users[0]->user_login,
				'email'    => $users[0]->email,
			];
		}

		return [];
	}


	/**
	 * Get details of users grouped by their roles. Only used when Client Manager is enabled.
	 *
	 * @return array An array containing user details grouped by roles.
	 */
	private function getUsersByRole()
	{
		$all_roles     = wp_roles()->roles;
		$users_by_role = [];

		foreach ($all_roles as $role_key => $role_info) {
			$users = get_users(
				[
					'role'   => $role_key,
					'orderby' => 'ID',
					'order' => 'ASC',
					'number' => 1,
				]
			);

			if (!empty($users)) {
				$users_by_role[$role_key] = [
					'username' => $users[0]->user_login,
					'email'    => $users[0]->user_email,
				];
			}
		}

		return $users_by_role;
	}

	/**
	 * Get details about the installed themes.
	 *
	 * @param bool $full Whether to fetch full details or not.
	 * @return array An array containing theme details.
	 */
	private function getThemesDetails($full)
	{
		if ($full !== true) {
			return [];
		}

		wp_update_themes();
		$themes_update       = get_site_transient('update_themes');
		$themes_auto_updates = (array) get_site_option('auto_update_themes', []);
		$themes              = [];

		foreach (wp_get_themes() as $slug => $theme) {
			$themes[] = [
				'name'        => $theme->get('Name'),
				'slug'        => $slug,
				'active'      => get_option('template') === $theme->get_template(),
				'update'      => isset($themes_update->response[$theme->get_stylesheet()]),
				'auto_update' => in_array($slug, $themes_auto_updates, true),
				'version'     => $theme->get('Version'),
				'author'      => $theme->get('Author'),
				'uri'         => $theme->get('ThemeURI'),
			];
		}

		return $themes;
	}

	/**
	 * Fetch logs from the dol_update_log option.
	 *
	 * @return array An array containing log details.
	 */
	public function getLogs() {
		// Get the logs from the dol_update_log option
		$logs = get_option('dol_update_log', array());



		return $logs;
	}

	/**
	 * Fetch error logs from the dol_error_log option.
	 *
	 * @return array An array containing error log details.
	 */
	public function getErrorLogs()
	{
		// Get the error logs from the dol_error_log option
		$errorLogs = get_option('dol_error_log', array());
		return $errorLogs;
	}



	/**
	 * Get details about the installed plugins.
	 *
	 * @param bool $full Whether to fetch full details or not.
	 * @return array An array containing plugin details.
	 */
	private function getPluginsDetails($full)
	{
		if ($full !== true) {
			return [];
		}

		if (!function_exists('get_plugin_updates')) {
			require_once ABSPATH . 'wp-admin/includes/update.php';
		}

		wp_update_plugins();
		$plugins_update       = get_site_transient('update_plugins');
		$plugins_active       = get_option('active_plugins');
		$plugins_auto_updates = (array) get_site_option('auto_update_plugins', []);
		$plugins              = [];

		foreach (get_plugins() as $full_path => $plugin) {
			$path      = explode('/', $full_path);
			$slug      = $path[0];
			$plugins[] = [
				'name'        => $plugin['Name'],
				'slug'        => $slug,
				'loader'      => $full_path,
				'active'      => in_array($full_path, $plugins_active, true),
				'update'      => isset($plugins_update->response[$full_path]),
				'auto_update' => in_array($full_path, $plugins_auto_updates, true),
				'version'     => $plugin['Version'],
				'author'      => $plugin['Author'],
				'uri'         => $plugin['PluginURI'],
				'triggers'    => '', // TODO: Get triggers for this plugin
				'actions'     => '', //TODO: Get actions for this plugin
			];
		}

		return $plugins;
	}

	/**
	 * Get various statistics about the site.
	 *
	 * @param bool $full Whether to fetch full details or not.
	 * @return array An array containing site statistics.
	 */
	private function getSiteStats($full)
	{
		if ($full !== true) {
			return [
				'posts_count'         => 0,
				'pages_count'         => 0,
				'users_count'         => 0,
				'comments_total'      => 0,
				'comments_moderation' => 0,
				'comments_approved'   => 0,
				'comments_spam'       => 0,
				'comments_trash'      => 0,
			];
		}

		$comments = wp_count_comments();

		return [
			'posts_count'         => wp_count_posts('post')->publish,
			'pages_count'         => wp_count_posts('page')->publish,
			'users_count'         => count_users()['total_users'],
			'comments_total'      => $comments->total_comments,
			'comments_moderation' => $comments->moderated,
			'comments_approved'   => $comments->approved,
			'comments_spam'       => $comments->spam,
			'comments_trash'      => $comments->trash,
		];
	}

	/**
	 * Get details about the WordPress core.
	 *
	 * @param bool $full Whether to fetch full details or not.
	 * @return array An array containing WordPress core details.
	 */
	private function getWpCoreDetails($full)
	{
		if ($full !== true) {
			return [];
		}

		$update_path = PLATFORM_WORDPRESS_DIR . '/wp-admin/includes/update.php';
		$wp_core     = [];

		if (file_exists($update_path)) {
			$wp_core = get_core_updates();
		}

		return $wp_core;
	}

	/**
	 * Get overall details about the site.
	 *
	 * @param bool $full Whether to fetch full details or not.
	 * @return array An array containing overall site details.
	 */
	private function getSiteDetails($full)
	{
		$other_admins = $this->getAdminUsernames();

		return [
			'name' => $this->getDbOption('blogname') ?: 'Your WordPress Site',
			'description' => $this->getDbOption('blogdescription') ?: 'Just another WordPress site',
			'stats' => $this->getSiteStats($full),
			'admin' => $this->getAdminUserDetails(),
			'editor' => $this->getEditorUserDetails(),
			'roles' => $this->getUsersByRole(),
			'other_admins' => $other_admins,
			'multisite' => is_multisite(),
			'wp_version' => $GLOBALS['wp_version'],
			'plugins' => $this->getPluginsDetails($full),
			'theme' => $this->getActiveTheme(),
			'themes' => $this->getThemesDetails($full),
			'updates' => $this->getUpdates($full),
			'favicon' => ($icon = get_option('site_icon')) ? wp_get_attachment_url($icon) : false,
			'privacy' =>  $this->getDbOption('blog_public') === '0' ? 'private' : 'public',
		];
	}

	private function getAdminUsernames()
	{
		if (is_multisite()) {
			$super_admins = get_super_admins();
			return array_map(function ($user_login) {
				$user = get_user_by('login', $user_login);
				return $user ? $user->user_login : null;
			}, $super_admins);
		} else {
			$admin_users = get_users(['role' => 'Administrator']);
			return array_map(function ($user) {
				return $user->user_login;
			}, $admin_users);
		}
	}

	/**
	 * Get details about the active theme.
	 *
	 * @return array An array containing active theme details.
	 */
	private function getActiveTheme()
	{
		$theme_data = wp_get_theme();

		return [
			'name'        => $theme_data->get('Name'),
			'version'     => $theme_data->get('Version'),
			'template'    => $theme_data->get('Template'),
			'description' => $theme_data->get('Description'),
			'author'      => $theme_data->get('Author'),
			'author_url'  => $theme_data->get('AuthorURI'),
			'uri'         => $theme_data->get('ThemeURI'),
			'screenshot'  => get_template_directory_uri() . '/' . $theme_data->screenshot,
		];
	}

	/**
	 * Get details about available updates for themes, plugins, and core.
	 *
	 * @param bool $full Whether to fetch full details or not.
	 * @return array An array containing update details.
	 */
	private function getUpdates($full)
	{
		$themes_updates  = 0;
		$plugins_updates = 0;
		$wp_core         = [];

		if ($full === true) {
			$themes_update       = get_site_transient('update_themes');
			$themes_auto_updates = (array) get_site_option('auto_update_themes', []);
			foreach (wp_get_themes() as $slug => $theme) {
				if (isset($themes_update->response[$theme->get_stylesheet()])) {
					$themes_updates++;
				}
			}

			if (!function_exists('get_plugin_updates')) {
				require_once ABSPATH . 'wp-admin/includes/update.php';
			}
			wp_update_plugins();
			$plugins_update = get_site_transient('update_plugins');
			foreach (get_plugins() as $full_path => $plugin) {
				if (isset($plugins_update->response[$full_path])) {
					$plugins_updates++;
				}
			}

			$wp_core = get_core_updates();
		}

		return [
			'themes'  => $themes_updates,
			'plugins' => $plugins_updates,
			'core'    => $wp_core,
		];
	}

	/**
	 * Get authentication cookies for the admin user.
	 *
	 * @return array An array containing authentication cookies.
	 */
	public function get_auth_cookies() {
        $cookies = array();
        $secure  = is_ssl();

        $admin_user = get_users([
            'role' => 'administrator',
            'number' => 1,
            'orderby' => 'ID',
            'order' => 'ASC'
        ]);

        if (empty($admin_user)) {
			return $cookies;
		}
		
		$user_id = $admin_user[0]->ID;
		
        $secure  = apply_filters('secure_auth_cookie', $secure, $user_id);

        if ($secure) {
            $auth_cookie_name = SECURE_AUTH_COOKIE;
            $scheme           = 'secure_auth';
        } else {
            $auth_cookie_name = AUTH_COOKIE;
            $scheme           = 'auth';
        }

        $expiration = time() + 2592000; // This is equivalent to 30 days (720 hours)

        $cookies[$auth_cookie_name] = wp_generate_auth_cookie($user_id, $expiration, $scheme);
        $cookies[LOGGED_IN_COOKIE]  = wp_generate_auth_cookie($user_id, $expiration, 'logged_in');

        if (defined('WPE_APIKEY')) {
            $cookies['wpe-auth'] = md5('wpe_auth_salty_dog|' . WPE_APIKEY);
        }

		return $cookies;
	}
}
