<?php

use PHPUnit\Framework\TestCase;
use SHServ\Middleware\ControlScripts;

class ScriptHelpersTest extends TestCase {
	protected $tb;

	protected function setUp(): void {
		$this -> tb = app() -> thin_builder;
		$this -> tb -> query("CREATE TABLE scripts (
			id INTEGER PRIMARY KEY AUTOINCREMENT,
			area_id INTEGER DEFAULT 0,
			uniq_name TEXT,
			type TEXT,
			state TEXT,
			params_schema TEXT,
			create_at TEXT,
			update_at TEXT
		)");
		if(!isset(app() -> scripts_registry)) {
			app() -> scripts_registry = new \SHServ\Middleware\ScriptsRegistry();
		}
		\Fury\Kernel\AppContainer::set_events(new \Fury\Kernel\Events());
		$this -> tb -> query("CREATE TABLE devices (
			id INTEGER PRIMARY KEY AUTOINCREMENT,
			area_id INTEGER DEFAULT 0,
			alias TEXT,
			name TEXT,
			device_type TEXT,
			device_ip TEXT,
			device_mac TEXT,
			device_hard_id TEXT,
			firmware_version TEXT,
			connection_status TEXT,
			status TEXT,
			description TEXT,
			last_contact TEXT,
			create_at TEXT,
			update_at TEXT
		)");
		ControlScripts::flush_statics();
	}

	protected function tearDown(): void {
		$this -> tb -> query("DROP TABLE IF EXISTS scripts");
		$this -> tb -> query("DROP TABLE IF EXISTS devices");
		ControlScripts::flush_statics();
	}

	// --- Action Generators ---

	public function test_add_toggle_action_registers_in_registry(): void {
		$scope = new class extends ControlScripts {
			public function register_sync_map(): void {}
			public function register_events_handlers(): void {}
			public function register_regular_scripts(): void {}
			public function register_actions_scripts(): void {
				$this -> add_toggle_action("test_toggle", "Test Toggle", "relay_a", 0, [
					"icon" => "<i></i>",
					"description" => "desc",
				]);
			}
		};

		$actions = ControlScripts::get_actions_scripts();
		$this -> assertArrayHasKey("test_toggle", $actions);
		$this -> assertEquals("Test Toggle", $actions["test_toggle"]["attributes"]["name"]);
		$this -> assertEquals("desc", $actions["test_toggle"]["attributes"]["description"]);
		$this -> assertNotNull($actions["test_toggle"]["script"]);
	}

	public function test_add_on_action_registers_in_registry(): void {
		$scope = new class extends ControlScripts {
			public function register_sync_map(): void {}
			public function register_events_handlers(): void {}
			public function register_regular_scripts(): void {}
			public function register_actions_scripts(): void {
				$this -> add_on_action("test_on", "Test On", "relay_b", 1);
			}
		};

		$actions = ControlScripts::get_actions_scripts();
		$this -> assertArrayHasKey("test_on", $actions);
		$this -> assertEquals("Test On", $actions["test_on"]["attributes"]["name"]);
	}

	public function test_add_off_action_registers_in_registry(): void {
		$scope = new class extends ControlScripts {
			public function register_sync_map(): void {}
			public function register_events_handlers(): void {}
			public function register_regular_scripts(): void {}
			public function register_actions_scripts(): void {
				$this -> add_off_action("test_off", "Test Off", "relay_c");
			}
		};

		$actions = ControlScripts::get_actions_scripts();
		$this -> assertArrayHasKey("test_off", $actions);
	}

	public function test_add_hatch_action_registers_in_registry(): void {
		$scope = new class extends ControlScripts {
			public function register_sync_map(): void {}
			public function register_events_handlers(): void {}
			public function register_regular_scripts(): void {}
			public function register_actions_scripts(): void {
				$this -> add_hatch_action("test_hatch", "Test Hatch", "hatch_x", "open", 50);
			}
		};

		$actions = ControlScripts::get_actions_scripts();
		$this -> assertArrayHasKey("test_hatch", $actions);
	}

	public function test_action_generators_return_false_on_duplicate_alias(): void {
		$scope = new class extends ControlScripts {
			public $r1;
			public $r2;
			public function register_sync_map(): void {}
			public function register_events_handlers(): void {}
			public function register_regular_scripts(): void {}
			public function register_actions_scripts(): void {
				$this -> r1 = $this -> add_toggle_action("dup", "Dup", "r", 0);
				$this -> r2 = $this -> add_toggle_action("dup", "Dup", "r", 0);
			}
		};

		$this -> assertTrue($scope -> r1);
		$this -> assertFalse($scope -> r2);
	}

	// --- Auto Button Bindings ---

	public function test_auto_button_bindings_registers_handlers(): void {
		$scope = new class extends ControlScripts {
			public function register_sync_map(): void {
				$this -> add_sync_connection([
					["type" => "relay", "alias" => "relay_1", "channel" => 0],
					["type" => "button", "alias" => "btn_1", "channel" => 0],
				]);
			}
			public function register_events_handlers(): void {}
			public function register_regular_scripts(): void {}
			public function register_actions_scripts(): void {}

			public function expose_auto_button_bindings(): void {
				$this -> auto_button_bindings([
					"btn_1" => ["mute" => [1, 2]],
				]);
			}
		};

		$scope -> expose_auto_button_bindings();

		// Verify that event handlers were registered (no exception + handlers present)
		$events = \Fury\Kernel\AppContainer::events();
		$this -> assertInstanceOf(\Fury\Kernel\Events::class, $events);
	}

	public function test_add_group_toggle_action_registers_in_registry(): void {
		$scope = new class extends ControlScripts {
			public function register_sync_map(): void {}
			public function register_events_handlers(): void {}
			public function register_regular_scripts(): void {}
			public function register_actions_scripts(): void {
				$this -> add_group_toggle_action("group_toggle_test", "Group Toggle", [
					"relay_a",
					["relay_b", 1],
				]);
			}
		};

		$actions = ControlScripts::get_actions_scripts();
		$this -> assertArrayHasKey("group_toggle_test", $actions);
		$this -> assertEquals("Group Toggle", $actions["group_toggle_test"]["attributes"]["name"]);
	}

	public function test_group_set_state_returns_false_for_missing_devices(): void {
		$scope = new class extends ControlScripts {
			public function register_sync_map(): void {}
			public function register_events_handlers(): void {}
			public function register_regular_scripts(): void {}
			public function register_actions_scripts(): void {}

			public function expose_group_set_state(Array $targets, bool $state): Array {
				return $this -> group_set_state($targets, $state);
			}
		};

		$results = $scope -> expose_group_set_state(["nonexistent_relay"], true);
		$this -> assertArrayHasKey("nonexistent_relay", $results);
		$this -> assertFalse($results["nonexistent_relay"]);
	}

	public function test_group_toggle_returns_false_for_missing_devices(): void {
		$scope = new class extends ControlScripts {
			public function register_sync_map(): void {}
			public function register_events_handlers(): void {}
			public function register_regular_scripts(): void {}
			public function register_actions_scripts(): void {}

			public function expose_group_toggle(Array $targets): Array {
				return $this -> group_toggle($targets);
			}
		};

		$results = $scope -> expose_group_toggle([["nonexistent_relay", 0]]);
		$this -> assertArrayHasKey("nonexistent_relay:0", $results);
		$this -> assertFalse($results["nonexistent_relay:0"]);
	}
}
