<?php

namespace SHServ\Models;

use \SHServ\Middleware\ControlScripts;
use \SHServ\Entities\Script;

class Scripts extends \SHServ\Middleware\Model {

	public function get_scopes_list(): Array {
		$instances = app() -> control_scripts_instances;
		$scopes = [];

		foreach($instances as $name => $scope) {
			$ref = new \ReflectionClass($scope);
			$path_info = pathinfo($ref -> getFileName());

			$scopes[] = [
				"name" => $name,
				"filename" => $path_info["basename"],
				"path" => $path_info["dirname"],
				"state" => $this -> script_state("scope", $name) ? "enabled" : "disabled"
			];
		}

		return $scopes;
	}

	public function remove_scope(String $name): Bool {
		$scopes = app() -> control_scripts_instances;

		if(!isset($scopes[$name])) {
			return false;
		}

		$ref = new \ReflectionClass($scopes[$name]);
		$filepath = $ref -> getFileName();

		if(!file_exists($filepath)) {
			return false;
		}

		if(!@unlink($filepath)) {
			return false;
		}

		$script = new Script($name);
		$script -> remove();

		return true;
	}

	public function script_state(String $type, String $uniq_name): Bool {
		$result = $this -> thin_builder() -> select(
			Script::$table_name,
			[ "state" ],
			[ ["type", "=", $type], "AND", [ "uniq_name", '=', $uniq_name ] ]
		);

		return !$result ? false : ($result[0]["state"] == "enabled");
	}

	public function select_scripts_by_aliases_types(String $type, Array $uniq_names): Array {
		$result = $this -> thin_builder() -> select(
			Script::$table_name,
			Script::get_fields(),
			[ ["type", "=", $type], "AND", [ "uniq_name", 'IN', $uniq_names ] ]
		);

		return !$result ? [] : array_map(function($item){
			return new Script($item["id"], $item);
		}, $result);
	}

	public function set_script_state(String $type, String $uniq_name, Bool $state): String | Bool {
		// Тут нужно проверить существует ли скрипт с таким именем
		
		if($type == "scope") {
			$scopes_names = array_map(function($scope) {
				return $scope["name"];
			}, $this -> get_scopes_list());

			if(!in_array($uniq_name, $scopes_names)) {
				return "scope_not_found"; // Err. Scope not exists
			}
		} elseif($type == "regular") {
			$regular_scripts_names = array_map(function($regular_script) {
				return $regular_script["alias"];
			}, $this -> regular_scripts_list());

			if(!in_array($uniq_name, $regular_scripts_names)) {
				return "regular_script_not_found"; // Err. Regular script not exists
			}
		} elseif($type == "action") {
			$action_scripts_names = array_map(function($action_script) {
				return $action_script["alias"];
			}, $this -> actions_scripts_list());

			if(!in_array($uniq_name, $action_scripts_names)) {
				return "action_script_not_found"; // Err. Action script not exists
			}
		} else {
			return "invalid_type"; // Err of type
		}

		$result = $this -> thin_builder() -> select(
			Script::$table_name,
			Script::get_fields(),
			[ ["type", "=", $type], "AND", [ "uniq_name", '=', $uniq_name ] ]
		);

		if(!$result) {
			return $this -> thin_builder() -> insert(
				Script::$table_name,
				[
					"uniq_name" => $uniq_name,
					"type" => $type,
					"state" => $state ? "enabled" : "disabled",
					"create_at" => date("Y-m-d H:i:s")
				]
			) ? true : "undefined_error";
		}

		// update
		$script = new Script($result[0]["id"], $result[0]);
		$script -> state = $state ? "enabled" : "disabled";
		return $script -> update() ? true : false;
	}

	public function enable_script(String $type, String $uniq_name): String | Bool {
		return $this -> set_script_state($type, $uniq_name, true);
	}

	public function disable_script(String $type, String $uniq_name): String | Bool {
		return $this -> set_script_state($type, $uniq_name, false);
	}

	public function regular_scripts_list(): Array {
		return $this -> get_scripts_list( "regular", ControlScripts::get_regular_scripts() );
	}

	public function actions_scripts_list(): Array {
		return $this -> get_scripts_list( "action", ControlScripts::get_actions_scripts() );
	}

	public function prepare_script_to_view(String $type, Array $script_from_control, $script_entity = null): Array {
		$prepared = [
			"alias" => $script_from_control["attributes"]["alias"],
			"type" => $type,
			"icon" => $script_from_control["attributes"]["icon"] ?? "",
			"code" => $script_from_control["code"] ?? "",
			"name" => $script_from_control["attributes"]["name"],
			"display_name" => $script_from_control["attributes"]["name"],
			"description" => $script_from_control["attributes"]["description"],
			"filename" => $script_from_control["attributes"]["filename"],
			"path" => $script_from_control["attributes"]["path"],
			"created_by" => $script_from_control["attributes"]["author"],
		];

		if($script_entity) {
			$prepared = array_merge($prepared, $script_entity -> to_array());
		} else {
			$prepared["state"] = (!$script_entity or $script_entity -> state != "enabled") ? "disabled" : "enabled";
		}

		return $prepared;
	}

	public function get_scripts_list(String $type, Array $scripts): Array {
		$scripts_entities = $this -> select_scripts_by_aliases_types($type, array_keys($scripts));
		
		$data = [];

		foreach($scripts as $alias => $script_data) {
			$script_entity = array_values(array_filter($scripts_entities, function($item) use($alias) {
				return $item -> uniq_name == $alias;
			}));

			$data[] = $this -> prepare_script_to_view($type, $script_data, $script_entity[0] ?? null);
		}

		return $data;
	}

	public function scope_is_exists(String $name): Bool {
		$instances = app() -> control_scripts_instances;

		return isset($instances[$name]);
	}
}