<?php

use PHPUnit\Framework\TestCase;
use SHServ\Controllers\DevicesRESTAPIController;

class DevicesRESTAPIControllerValidationTest extends TestCase {
	protected $tb;
	protected $controller;

	protected function setUp(): void {
		$this -> tb = app() -> thin_builder;
		$this -> tb -> query("CREATE TABLE devices (
			id INTEGER PRIMARY KEY AUTOINCREMENT,
			area_id INTEGER,
			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
		)");
		$this -> controller = new DevicesRESTAPIController();
	}

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

	private function decode(string $json): array {
		return json_decode($json, true);
	}

	public function test_setup_new_device_rejects_invalid_ip(): void {
		$result = $this -> controller -> setup_new_device('999.999.999.999', 'relay_1', 'Relay', '');
		$data = $this -> decode($result);
		$this -> assertFalse($data['status']);
		$this -> assertSame('invalid_ip', $data['error_alias']);
		$this -> assertContains('device_ip', $data['failed_fields']);
	}

	public function test_setup_new_device_rejects_invalid_alias(): void {
		$result = $this -> controller -> setup_new_device('192.168.1.1', 'bad-alias', 'Relay', '');
		$data = $this -> decode($result);
		$this -> assertFalse($data['status']);
		$this -> assertSame('invalid_alias', $data['error_alias']);
		$this -> assertContains('alias', $data['failed_fields']);
	}

	public function test_setup_new_device_rejects_empty_name(): void {
		$result = $this -> controller -> setup_new_device('192.168.1.1', 'relay_1', '', '');
		$data = $this -> decode($result);
		$this -> assertFalse($data['status']);
		$this -> assertSame('empty_field', $data['error_alias']);
		$this -> assertContains('name', $data['failed_fields']);
	}

	public function test_setup_new_device_rejects_duplicate_alias(): void {
		$this -> tb -> insert('devices', [
			'alias' => 'relay_1',
			'name' => 'Relay',
			'device_type' => 'relay',
			'status' => 'active',
			'create_at' => date('Y-m-d H:i:s'),
		]);

		$result = $this -> controller -> setup_new_device('192.168.1.1', 'relay_1', 'Relay', '');
		$data = $this -> decode($result);
		$this -> assertFalse($data['status']);
		$this -> assertSame('alias_already_exists', $data['error_alias']);
		$this -> assertContains('alias', $data['failed_fields']);
	}

	public function test_do_device_action_rejects_invalid_action(): void {
		$this -> tb -> insert('devices', [
			'alias' => 'relay_1',
			'name' => 'Relay',
			'device_type' => 'relay',
			'device_ip' => '192.168.1.1',
			'status' => 'active',
			'create_at' => date('Y-m-d H:i:s'),
		]);

		$result = $this -> controller -> do_device_action(1, 'BAD!', []);
		$data = $this -> decode($result);
		$this -> assertFalse($data['status']);
		$this -> assertSame('invalid_action', $data['error_alias']);
		$this -> assertContains('action', $data['failed_fields']);
	}

	public function test_do_device_action_rejects_invalid_json_params(): void {
		$this -> tb -> insert('devices', [
			'alias' => 'relay_1',
			'name' => 'Relay',
			'device_type' => 'relay',
			'device_ip' => '192.168.1.1',
			'status' => 'active',
			'create_at' => date('Y-m-d H:i:s'),
		]);

		$result = $this -> controller -> do_device_action(1, 'toggle', '{bad}');
		$data = $this -> decode($result);
		$this -> assertFalse($data['status']);
		$this -> assertSame('invalid_json', $data['error_alias']);
		$this -> assertContains('params', $data['failed_fields']);
	}

	public function test_do_device_action_rejects_non_array_params(): void {
		$this -> tb -> insert('devices', [
			'alias' => 'relay_1',
			'name' => 'Relay',
			'device_type' => 'relay',
			'device_ip' => '192.168.1.1',
			'status' => 'active',
			'create_at' => date('Y-m-d H:i:s'),
		]);

		$result = $this -> controller -> do_device_action(1, 'toggle', 123);
		$data = $this -> decode($result);
		$this -> assertFalse($data['status']);
		$this -> assertSame('invalid_params', $data['error_alias']);
		$this -> assertContains('params', $data['failed_fields']);
	}

	public function test_update_alias_rejects_invalid_alias(): void {
		$this -> tb -> insert('devices', [
			'alias' => 'relay_1',
			'name' => 'Relay',
			'device_type' => 'relay',
			'status' => 'active',
			'create_at' => date('Y-m-d H:i:s'),
		]);

		$result = $this -> controller -> update_alias(1, 'BAD!');
		$data = $this -> decode($result);
		$this -> assertFalse($data['status']);
		$this -> assertSame('invalid_alias', $data['error_alias']);
		$this -> assertContains('new_alias', $data['failed_fields']);
	}

	public function test_update_alias_rejects_duplicate_alias(): void {
		$this -> tb -> insert('devices', [
			'alias' => 'relay_1',
			'name' => 'Relay 1',
			'device_type' => 'relay',
			'status' => 'active',
			'create_at' => date('Y-m-d H:i:s'),
		]);
		$this -> tb -> insert('devices', [
			'alias' => 'relay_2',
			'name' => 'Relay 2',
			'device_type' => 'relay',
			'status' => 'active',
			'create_at' => date('Y-m-d H:i:s'),
		]);

		$result = $this -> controller -> update_alias(2, 'relay_1');
		$data = $this -> decode($result);
		$this -> assertFalse($data['status']);
		$this -> assertSame('alias_already_exists', $data['error_alias']);
		$this -> assertContains('new_alias', $data['failed_fields']);
	}

	public function test_update_alias_allows_same_alias(): void {
		$this -> tb -> insert('devices', [
			'alias' => 'relay_1',
			'name' => 'Relay',
			'device_type' => 'relay',
			'status' => 'active',
			'create_at' => date('Y-m-d H:i:s'),
		]);

		$result = $this -> controller -> update_alias(1, 'relay_1');
		$data = $this -> decode($result);
		$this -> assertTrue($data['status']);
	}

	public function test_devices_list_rejects_wrong_status(): void {
		$result = $this -> controller -> devices_list('invalid_status');
		$data = $this -> decode($result);
		$this -> assertFalse($data['status']);
		$this -> assertSame('wrong_status_name', $data['error_alias']);
	}

	public function test_place_in_area_rejects_invalid_target_id(): void {
		$result = $this -> controller -> place_in_area(0, 1);
		$data = $this -> decode($result);
		$this -> assertFalse($data['status']);
		$this -> assertSame('invalid_id', $data['error_alias']);
		$this -> assertContains('target_id', $data['failed_fields']);
	}

	public function test_unassign_from_area_rejects_invalid_id(): void {
		$result = $this -> controller -> unassign_from_area(0);
		$data = $this -> decode($result);
		$this -> assertFalse($data['status']);
		$this -> assertSame('invalid_id', $data['error_alias']);
		$this -> assertContains('target_id', $data['failed_fields']);
	}

	public function test_update_name_rejects_empty_name(): void {
		$this -> tb -> insert('devices', [
			'alias' => 'relay_1',
			'name' => 'Relay',
			'device_type' => 'relay',
			'status' => 'active',
			'create_at' => date('Y-m-d H:i:s'),
		]);

		$result = $this -> controller -> update_name(1, '');
		$data = $this -> decode($result);
		$this -> assertFalse($data['status']);
		$this -> assertSame('empty_field', $data['error_alias']);
		$this -> assertContains('name', $data['failed_fields']);
	}
}
