<?php

/**
 * Vvveb
 *
 * Copyright (C) 2022  Ziadin Givan
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License as
 * published by the Free Software Foundation, either version 3 of the
 * License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Affero General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with this program.  If not, see <https://www.gnu.org/licenses/>.
 *
 */

namespace Vvveb\System\Extensions;

use \Vvveb\System\Cache;
use function Vvveb\rcopy;
use function Vvveb\rrmdir;
use Vvveb\System\Event;

class Plugins extends Extensions {
	static protected $url = 'https://plugins.vvveb.com';

	static protected $feedUrl = 'https://plugins.vvveb.com/feed/plugins';

	static protected $categoriesFeedUrl = 'https://plugins.vvveb.com/feed/categories';

	static protected $extension = 'plugin';

	static protected $loaded  = false;

	static protected $baseDir = DIR_PLUGINS;

	static protected $plugins = [];

	static protected $categories = [];

	static function clearPluginsCache($site_id = SITE_ID) {
		$cacheDriver = Cache :: getInstance();
		$cacheKey    = "plugins_list_$site_id";
		$cacheDriver->delete('vvveb', $cacheKey);
	}

	static function getInfo($content, $name = false) {
		$params               = parent::getInfo($content, $name);
		$params['status']     = 'inactive';

		if (isset($params['thumb']) &&
			file_exists(DIR_PUBLIC . ($file = 'plugins/' . $name . '/' . $params['thumb']))) {
			$params['thumb_url'] = PUBLIC_PATH . $file;
		} else {
			$params['thumb_url'] = PUBLIC_PATH . 'media/extension.svg';
		}

		return $params;
	}

	static function loadPlugin($pluginName) {
		$file = DIR_PLUGINS . $pluginName . '/plugin.php';

		if (file_exists($file)) {
			return include $file;
		}

		return false;
	}

	static function activate($pluginName, $site_id = SITE_ID) {
		if (! $pluginName) {
			return;
		}

		$file = DIR_PLUGINS . $pluginName . '/plugin.php';

		if (file_exists($file)) {
			$key    = "plugins.$site_id.$pluginName.status";
			$status = \Vvveb\getConfig($key);

			if (! $status) {
				//if no plugin info then this is first activation, run plugin setup
				Event :: trigger(__CLASS__, 'setup', $pluginName, $site_id);
			}

			$return = \Vvveb\setConfig($key, 'active');
			Event :: trigger(__CLASS__, __FUNCTION__, $pluginName, $site_id);

			self :: clearPluginsCache($site_id);
			self :: copyPublicDir($pluginName);

			return $return;
		}

		return false;
	}

	static function deactivate($pluginName, $site_id = SITE_ID) {
		if (! $pluginName) {
			return;
		}
		$key    = "plugins.$site_id.$pluginName.status";
		$return = \Vvveb\setConfig($key, 'inactive');
		/*
		$key    = "plugins.$site_id.$pluginName";
		$return = \Vvveb\unsetConfig($key, []);
		*/
		Event :: trigger(__CLASS__, __FUNCTION__, $pluginName, $site_id);

		self :: clearPluginsCache($site_id);

		return $return;
	}

	//copy plugin public folder to public/plugins folder
	static function copyPublicDir($pluginName) {
		if ($pluginName) {
			$publicSrc  = DIR_PLUGINS . "$pluginName/public";
			$publicDest = DIR_PUBLIC . "plugins/$pluginName";

			if (! file_exists($publicDest)) {
				//try symlink first
				if (symlink($publicSrc, $publicDest)) {
					return true;
				} else {
					return rcopy($publicSrc, $publicDest);
				}
			} else {
				return false;
			}
		}
	}

	static function install($zipFile, $slug = false, $validate = true) {
		if ($pluginName = parent :: install($zipFile, $validate)) {
			if (self :: copyPublicDir($pluginName)) {
				self :: clearPluginsCache();

				return $pluginName;
			}
		}
	}

	static function uninstall($pluginName, $site_id = SITE_ID) {
		$success = false;
		//remove public folder from public/plugins/$pluginName
		$pluginDir  = DIR_PLUGINS . "$pluginName";
		$publicDir  = DIR_PUBLIC . "plugins/$pluginName";

		if (file_exists($publicDir)) {
			if (is_link($publicDir)) {
				unlink($publicDir);
			} else {
				if (is_dir($publicDir)) {
					rrmdir($publicDir);
				}
			}
		}

		$success = rrmdir($pluginDir);

		$key    = "plugins.$site_id.$pluginName";
		\Vvveb\unsetConfig($key, []);
		self :: clearPluginsCache($site_id);

		Event :: trigger(__CLASS__, __FUNCTION__, $pluginName, $success);

		return $success;
	}

	static function getList($site_id = SITE_ID, $category = false, $cache = true) {
		$cacheDriver = Cache :: getInstance();
		$cacheKey    = "plugins_list_$site_id";

		if (! $category && $cache && $result = $cacheDriver->get('vvveb', $cacheKey)) {
			return $result;
		} else {
			$pluginList   = parent :: getListInfo(DIR_PLUGINS . '/*/plugin.php');
			$pluginConfig = [];

			if ($site_id) {
				$pluginConfig = \Vvveb\config("plugins.$site_id", []);
			}

			if (is_array($pluginConfig)) {
				$pluginList = array_replace_recursive($pluginList, $pluginConfig);
			}

			//set default name to show the plugin as broken if is missing
			array_walk($pluginList, function (&$val, $key) use (&$pluginList, $category) {
				if (! isset($val['name'])) {
					$val['slug'] = $key;
					$val['name'] = sprintf('[%s]', $key);
					$val['status'] = 'broken';
				}

				if ($category && (! isset($val['category']) || ($val['category'] != $category))) {
					unset($pluginList[$key]);
				}
			});

			if (! $category && $cache) {
				$cacheDriver->set('vvveb', $cacheKey, $pluginList);
				$cacheDriver->set('vvveb', "{$cacheKey}_categories", static :: $categories);
			}

			return $pluginList;
		}
	}

	static function getCategories($site_id = SITE_ID) {
		if (! static :: $categories) {
			$cacheDriver          = Cache :: getInstance();
			$cacheKey             = "plugins_list_{$site_id}_categories";
			static :: $categories = $cacheDriver->get('vvveb', $cacheKey);
		}

		return static :: $categories;
	}

	static function loadPlugins($site_id = SITE_ID) {
		if (static :: $loaded) {
			return;
		}
		static :: $loaded = true;

		$plugins = static::getList($site_id);

		foreach ($plugins as $name => $plugin) {
			if ((isset($plugin['status']) && $plugin['status'] == 'active')
				&& file_exists($plugin['file'])) {
				include $plugin['file'];
			}
		}
	}
}
