<?php

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

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

	protected function setUp(): void {
		$this -> tb = app() -> thin_builder;
		$this -> tb -> query("CREATE TABLE areas (
			id INTEGER PRIMARY KEY AUTOINCREMENT,
			alias TEXT,
			display_name TEXT,
			type TEXT,
			parent_id INTEGER DEFAULT 0,
			schema TEXT,
			create_at TEXT,
			update_at TEXT
		)");
		$this -> controller = new AreasRESTAPIController();
	}

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

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

	public function test_new_area_rejects_invalid_alias(): void {
		$result = $this -> controller -> new_area('room', 'bad-alias!', 'Room');
		$data = $this -> decode($result);
		$this -> assertFalse($data['status']);
		$this -> assertSame('invalid_alias', $data['error_alias']);
		$this -> assertContains('alias', $data['failed_fields']);
	}

	public function test_new_area_rejects_empty_type(): void {
		$result = $this -> controller -> new_area('', 'room_1', 'Room');
		$data = $this -> decode($result);
		$this -> assertFalse($data['status']);
		$this -> assertSame('empty_field', $data['error_alias']);
		$this -> assertContains('type', $data['failed_fields']);
	}

	public function test_new_area_rejects_empty_display_name(): void {
		$result = $this -> controller -> new_area('room', 'room_1', '');
		$data = $this -> decode($result);
		$this -> assertFalse($data['status']);
		$this -> assertSame('empty_field', $data['error_alias']);
		$this -> assertContains('display_name', $data['failed_fields']);
	}

	public function test_new_area_rejects_duplicate_alias(): void {
		$this -> tb -> insert('areas', [
			'alias' => 'room_1',
			'display_name' => 'Room',
			'type' => 'room',
			'parent_id' => 0,
			'create_at' => date('Y-m-d H:i:s'),
		]);

		$result = $this -> controller -> new_area('room', 'room_1', 'Room');
		$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_remove_area_rejects_invalid_id(): void {
		$result = $this -> controller -> remove_area(0);
		$data = $this -> decode($result);
		$this -> assertFalse($data['status']);
		$this -> assertSame('invalid_id', $data['error_alias']);
		$this -> assertContains('area_id', $data['failed_fields']);
	}

	public function test_update_alias_rejects_invalid_alias(): void {
		$this -> tb -> insert('areas', [
			'alias' => 'old',
			'display_name' => 'Old',
			'type' => 'room',
			'parent_id' => 0,
			'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('areas', [
			'alias' => 'existing',
			'display_name' => 'Existing',
			'type' => 'room',
			'parent_id' => 0,
			'create_at' => date('Y-m-d H:i:s'),
		]);
		$this -> tb -> insert('areas', [
			'alias' => 'old',
			'display_name' => 'Old',
			'type' => 'room',
			'parent_id' => 0,
			'create_at' => date('Y-m-d H:i:s'),
		]);

		$result = $this -> controller -> update_alias(2, 'existing');
		$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_update_alias_allows_same_alias(): void {
		$this -> tb -> insert('areas', [
			'alias' => 'old',
			'display_name' => 'Old',
			'type' => 'room',
			'parent_id' => 0,
			'create_at' => date('Y-m-d H:i:s'),
		]);

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

	public function test_update_display_name_rejects_empty_name(): void {
		$this -> tb -> insert('areas', [
			'alias' => 'room',
			'display_name' => 'Room',
			'type' => 'room',
			'parent_id' => 0,
			'create_at' => date('Y-m-d H:i:s'),
		]);

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

	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_place_in_area_rejects_invalid_place_in_area_id(): void {
		$result = $this -> controller -> place_in_area(1, 0);
		$data = $this -> decode($result);
		$this -> assertFalse($data['status']);
		$this -> assertSame('invalid_id', $data['error_alias']);
		$this -> assertContains('place_in_area_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']);
	}
}
