<?php

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

class AreasControllerHappyPathTest extends TestCase {
	private $tb;
	private $controller;

	protected function setUp(): void {
		$this -> tb = app() -> thin_builder;
		$this -> create_areas_table();
		$this -> create_devices_table();
		$this -> controller = new AreasRESTAPIController();
	}

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

	private function create_areas_table(): void {
		$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
		)");
	}

	private function create_devices_table(): void {
		$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
		)");
	}

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

	public function test_new_area_creates_area(): void {
		$result = $this -> controller -> new_area('room', 'kitchen', 'Kitchen');
		$data = $this -> decode($result);

		$this -> assertTrue($data['status']);
		$this -> assertSame('kitchen', $data['data']['alias']);
		$this -> assertSame('Kitchen', $data['data']['area']['display_name']);
		$this -> assertSame('room', $data['data']['area']['type']);

		$rows = $this -> tb -> select('areas', ['id'], [['alias', '=', 'kitchen']]);
		$this -> assertCount(1, $rows);
	}

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

		$result = $this -> controller -> areas_list();
		$data = $this -> decode($result);

		$this -> assertTrue($data['status']);
		$this -> assertCount(2, $data['data']['areas']);
		$this -> assertSame(2, $data['data']['total']);
	}

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

		$result = $this -> controller -> update_display_name(1, 'Main Hall');
		$data = $this -> decode($result);

		$this -> assertTrue($data['status']);
		$this -> assertSame('Main Hall', $data['data']['area']['display_name']);

		$rows = $this -> tb -> select('areas', ['display_name'], [['id', '=', 1]]);
		$this -> assertSame('Main Hall', $rows[0]['display_name']);
	}

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

		$result = $this -> controller -> update_alias(1, 'new_alias');
		$data = $this -> decode($result);

		$this -> assertTrue($data['status']);
		$this -> assertSame('new_alias', $data['data']['alias']);

		$rows = $this -> tb -> select('areas', ['alias'], [['id', '=', 1]]);
		$this -> assertSame('new_alias', $rows[0]['alias']);
	}

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

		$result = $this -> controller -> remove_area(1);
		$data = $this -> decode($result);

		$this -> assertTrue($data['status']);

		$rows = $this -> tb -> select('areas', ['id'], [['alias', '=', 'to_remove']]);
		$this -> assertCount(0, $rows);
	}

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

		$result = $this -> controller -> place_in_area(2, 1);
		$data = $this -> decode($result);

		$this -> assertTrue($data['status']);

		$rows = $this -> tb -> select('areas', ['parent_id'], [['id', '=', 2]]);
		$this -> assertSame(1, $rows[0]['parent_id']);
	}

	public function test_exists_types_returns_unique_types(): void {
		$this -> tb -> insert('areas', [
			'alias' => 'a1', 'display_name' => 'A1', 'type' => 'room',
			'parent_id' => 0, 'create_at' => date('Y-m-d H:i:s'),
		]);
		$this -> tb -> insert('areas', [
			'alias' => 'a2', 'display_name' => 'A2', 'type' => 'room',
			'parent_id' => 0, 'create_at' => date('Y-m-d H:i:s'),
		]);
		$this -> tb -> insert('areas', [
			'alias' => 'a3', 'display_name' => 'A3', 'type' => 'floor',
			'parent_id' => 0, 'create_at' => date('Y-m-d H:i:s'),
		]);

		$result = $this -> controller -> exists_types();
		$data = $this -> decode($result);

		$this -> assertTrue($data['status']);
		$this -> assertContains('room', $data['data']['types']);
		$this -> assertContains('floor', $data['data']['types']);
		$this -> assertCount(2, $data['data']['types']);
	}
}
