<?php

/*
TODO:
 + Создание метода для получения state скрипта
 + Вывод списков скриптов с полем state
 + Интегрировать поведение относительно поля state при запуске скриптов. Выключенные скрипты не должны быть запущены.
 - Реализовать апдейт скриптов
 */

namespace SHServ\Controllers;

use \SHServ\Middleware\ControlScripts;
use \SHServ\Models\Scripts;
use \SHServ\Entities\Script;
use \SHServ\Entities\Area;
use \SHServ\Integrations\GAuth\AuthControllerTrait;

class ScriptsRESTAPIController extends \SHServ\Middleware\Controller {
	use AuthControllerTrait;
	public function run_action_script($alias, $params) {
		if ($auth = $this -> require_permission('scripts.run')) { return $auth; }
		if(is_string($params)) {
			$decoded = json_decode($params, true);
			if(json_last_error() !== JSON_ERROR_NONE) {
				logging() -> warn('php:Scripts', 'Run action script failed: invalid JSON params', ['alias' => $alias]);
				return $this -> utils() -> response_error("invalid_json", ["params"]);
			}
			$params = $decoded;
		}

		if(!is_array($params)) {
			logging() -> warn('php:Scripts', 'Run action script failed: invalid params', ['alias' => $alias]);
			return $this -> utils() -> response_error("invalid_params", ["params"]);
		}

		if(!preg_match('/^[a-z0-9_]+$/', $alias) || strlen($alias) > 255) {
			logging() -> warn('php:Scripts', 'Run action script failed: invalid alias', ['alias' => $alias]);
			return $this -> utils() -> response_error("invalid_alias", ["alias"]);
		}

		logging() -> info('php:Scripts', 'Run action script', ['alias' => $alias]);

		$result = ControlScripts::run_action_script($alias, $params);

		if(!$result) {
			logging() -> warn('php:Scripts', 'Run action script failed: not found or disabled', ['alias' => $alias]);
			return $this -> utils() -> response_error("action_script_not_found");
		}

		logging() -> info('php:Scripts', 'Run action script successful', ['alias' => $alias, 'exec_time' => $result['exec_time'] ?? null]);
		return $this -> utils() -> response_success([
			"return" => $result
		]);
	}

	public function actions_scripts_list() {
		if ($auth = $this -> require_permission('scripts.view')) { return $auth; }
		$data = (new Scripts()) -> actions_scripts_list();

		logging() -> trace('php:Scripts', 'Action scripts list fetched', ['total' => count($data)]);

		return $this -> utils() -> response_success([
			"scripts" => $data,
			"total" => count($data)
		]);
	}

	public function regular_scripts_list() {
		if ($auth = $this -> require_permission('scripts.view')) { return $auth; }
		$data = (new Scripts()) -> regular_scripts_list();

		logging() -> trace('php:Scripts', 'Regular scripts list fetched', ['total' => count($data)]);

		return $this -> utils() -> response_success([
			"scripts" => $data,
			"total" => count($data)
		]);
	}

	public function scope_list() {
		if ($auth = $this -> require_permission('scripts.view')) { return $auth; }
		$scripts_model = new Scripts();
		$scopes = $scripts_model -> get_scopes_list();

		logging() -> trace('php:Scripts', 'Scope list fetched', ['total' => count($scopes)]);

		return $this -> utils() -> response_success([
			"scopes" => $scopes,
			"total" => count($scopes)
		]);
	}

	public function scope_file($name) {
		if ($auth = $this -> require_permission('scripts.view')) { return $auth; }
		$scripts_model = new Scripts();
		$scopes = $scripts_model -> get_scopes_list();

		$file = "";
		foreach($scopes as $scope) {
			if($name != $scope["name"]) {
				continue;
			}

			$file = file_get_contents($scope["path"] . "/" . $scope["filename"]);

			break;
		}

		if(!$file) {
			return $this -> utils() -> response_error("scope_not_found");
		}

		return $this -> utils() -> response_success(["source" => $file]);
	}

	public function scope_remove($name) {
		if ($auth = $this -> require_permission('scripts.edit')) { return $auth; }
		logging() -> warn('php:Scripts', 'Remove scope', ['scope_name' => $name]);
		return (new Scripts()) -> remove_scope($name)
			? $this -> utils() -> response_success()
			: $this -> utils() -> response_error("undefined_error");
	}

	protected function set_script_state(String $type, String $uniq_name, String $state) {
		if ($auth = $this -> require_permission('scripts.edit')) { return $auth; }
		if(!in_array($state, ["enable", "disable"], true)) {
			logging() -> warn('php:Scripts', 'Set script state failed: invalid state', ['type' => $type, 'alias' => $uniq_name, 'state' => $state]);
			return $this -> utils() -> response_error("invalid_state", ["state"]);
		}

		if($state == "enable") {
			$result = (new Scripts()) -> enable_script($type, $uniq_name);
		} else {
			$result = (new Scripts()) -> disable_script($type, $uniq_name);
		}

		if ($result === true) {
			logging() -> info('php:Scripts', 'Script state changed', ['type' => $type, 'alias' => $uniq_name, 'state' => $state]);
			return $this -> utils() -> response_success();
		}

		logging() -> warn('php:Scripts', 'Set script state failed', ['type' => $type, 'alias' => $uniq_name, 'state' => $state, 'error' => $result]);
		return $this -> utils() -> response_error($result);
	}

	public function set_scope_state($uniq_name, $state) {
		return $this -> set_script_state("scope", $uniq_name, $state);
	}

	public function set_regular_script_state($uniq_name, $state) {
		return $this -> set_script_state("regular", $uniq_name, $state);
	}

	public function set_action_script_state($uniq_name, $state) {
		return $this -> set_script_state("action", $uniq_name, $state);
	}

	public function place_in_area($target_id, $place_in_area_id) {
		if ($auth = $this -> require_permission('scripts.edit')) { return $auth; }
		if($target_id != intval($target_id) or intval($target_id) < 1) {
			return $this -> utils() -> response_error("invalid_id", ["target_id"]);
		}

		if($place_in_area_id != intval($place_in_area_id) or intval($place_in_area_id) < 1) {
			return $this -> utils() -> response_error("invalid_id", ["place_in_area_id"]);
		}

		$script = new Script(intval($target_id));
		$place_area = new Area(intval($place_in_area_id));

		if(!$script) {
			logging() -> warn('php:Scripts', 'Place script in area failed: not found', ['script_id' => $target_id]);
			return $this -> utils() -> response_error("script_not_exists");
		}

		if(!$place_area) {
			logging() -> warn('php:Scripts', 'Place script in area failed: area not found', ['area_id' => $place_in_area_id]);
			return $this -> utils() -> response_error("area_not_exists");
		}

		logging() -> info('php:Scripts', 'Place script in area', ['script_id' => $script -> id(), 'alias' => $script -> alias, 'area_id' => $place_area -> id()]);

		if(!$script -> place_in_area($place_area)) {
			logging() -> warn('php:Scripts', 'Place script in area failed', ['script_id' => $script -> id(), 'area_id' => $place_area -> id()]);
			return $this -> utils() -> response_error("undefined_error");
		}

		return $this -> utils() -> response_success();
	}

	public function unassign_from_area($target_id) {
		if ($auth = $this -> require_permission('scripts.edit')) { return $auth; }
		if($target_id != intval($target_id) or intval($target_id) < 1) {
			return $this -> utils() -> response_error("invalid_id", ["target_id"]);
		}

		$script = new Script(intval($target_id));

		if(!$script) {
			logging() -> warn('php:Scripts', 'Unassign script from area failed: not found', ['script_id' => $target_id]);
			return $this -> utils() -> response_error("script_not_exists");
		}

		logging() -> info('php:Scripts', 'Unassign script from area', ['script_id' => $script -> id(), 'alias' => $script -> alias]);

		return $script -> place_in_area_id(0)
			? $this -> utils() -> response_success()
			: $this -> utils() -> response_error("undefined_error");
	}
}