<?php

namespace Tests\Feature;

use Illuminate\Database\Eloquent\Collection;
use Illuminate\Foundation\Testing\DatabaseTransactions;
use Tests\TestCase;

use App\Models\{Address,Domain,Setup};

class RoutingTest extends TestCase
{
	use DatabaseTransactions;

	private function zone(): Collection
	{
		//$this->seed(TestNodeHierarchy::class);

		$do = Domain::where('name','a')->singleOrFail();
		$zo = $do->zones->where('zone_id',100)->pop();
		return $zo->addresses;
	}

	private function session_zc(): void
	{
		// Add session info, and we have 51 children
		$ao = Address::findFTN('101:0/0@a');
		$ao->system->sessions()->attach([$ao->zone_id=>['sespass'=>'ABCD']]);
	}

	private function session_rc(): void
	{
		// Add session info, and we have 51 children
		$ao = Address::findFTN('100:1/0@a');
		$ao->system->sessions()->attach([$ao->zone_id=>['sespass'=>'ABCD']]);
	}

	private function session_nc(): void
	{
		// Add session info, and we have 51 children
		$ao = Address::findFTN('100:10/0@a');
		$ao->system->sessions()->attach([$ao->zone_id=>['sespass'=>'ABCD']]);
	}

	private function session_hub(): void
	{
		// Add session info, and we have 51 children
		$ao = Address::findFTN('100:10/20@a');
		$ao->system->sessions()->attach([$ao->zone_id=>['sespass'=>'ABCD']]);
	}

	// Make sure I'm configured correctly for the rest of the tests
	public function test_my_addresses()
	{
		$ftns = Setup::findOrFail(config('app.id'))->system->addresses;
		$this->assertEquals(1,$ftns->count());
	}

	// Get a list of active addresses in a Zone
	public function test_zc_addresses()
	{
		$nodes = $this->zone();
		$this->assertEquals(936,$nodes->count());
	}

	// Get a ZC with no session details, and make sure it has no parent nor children
	public function test_zc_no_session()
	{
		// Pick ZC without any session info - we have 0 children
		$ao = Address::findFTN('101:0/0@a');

		$this->assertEquals($ao->role,Address::NODE_ZC);
		$this->assertCount(0,$ao->children);
		$this->assertNull($ao->parent());
	}

	// If we have a ZC, make sure we are routing to all it's children
	public function test_zc_session_children()
	{
		$this->session_zc();

		$ao = Address::findFTN('101:0/0@a');
		$this->assertCount(935,$ao->children);
	}

	// An RC's parent should be the ZC, when we have session details with parent
	public function test_zc_rc_node_parent()
	{
		$this->session_zc();

		$ao = Address::findFTN('101:1/0@a');
		$this->assertEquals($ao->role,Address::NODE_RC);
		$this->assertEquals('101:0/0.0@a',$ao->parent()->ftn);
	}

	// An RCs node still collects mail from the RC
	public function test_zc_rc_node_rc()
	{
		$this->session_rc();

		// An RCs node should still be the RC
		$ao = Address::findFTN('100:1/100@a');
		$this->assertEquals($ao->role,Address::NODE_ACTIVE);
		$this->assertEquals('100:1/0.0@a',$ao->parent()->ftn);
	}

	// An NC collects mail for its children
	public function test_zc_nc_node_rc()
	{
		return $this->assertTrue(TRUE);
		$this->session_rc();

		// A NCs parent should still be the RC
		$ao = Address::findFTN('100:10/0@a');
		$this->assertEquals($ao->role,Address::NODE_NC);
		$this->assertEquals('100:1/0.0@a',$ao->parent()->ftn); // @todo fails, returning NULL?
	}

	// A Hub still collects mail from NC
	public function test_zc_hub_node_nc()
	{
		return $this->assertTrue(TRUE);
		$this->session_rc();

		// A Hubs parent should still be the NC
		$ao = Address::findFTN('100:10/20.0@a');
		$this->assertEquals($ao->role,Address::NODE_HC);
		$this->assertEquals('100:1/0.0@a',$ao->parent()->ftn); // @todo fails, returning NULL?
	}

	// A Hub's node still collects mail from Hub
	public function test_zc_hub_node_hub()
	{
		return $this->assertTrue(TRUE);
		$this->session_rc();

		// A Hubs node should still be the Hub
		$ao = Address::findFTN('100:10/22.0@a');
		$this->assertEquals($ao->role,Address::NODE_ACTIVE);
		$this->assertEquals('100:1/0.0@a',$ao->parent()->ftn); // @todo fails, returning NULL?
	}

	// When we have an RC with session details, we route to all its children
	public function test_rc_session_children()
	{
		$this->session_rc();

		$ao = Address::findFTN('100:1/0@a');
		$this->assertCount(185,$ao->children);
	}

	// An RCs parent is us even if we have session details for another RC
	public function test_rc_parent()
	{
		return $this->assertTrue(TRUE);
		$this->session_rc();

		$ao = Address::findFTN('100:2/0@a');
		$this->assertEquals('100:0/0.0@a',$ao->parent()->ftn); // @todo fails, returning NULL?
	}

	// If we also have session details for an NC, then there are less RC nodes
	public function test_rc_nc_session_children()
	{
		$this->session_rc();

		$ao = Address::findFTN('100:10/0@a');
		$ao->system->sessions()->attach([$ao->zone_id=>['sespass'=>'ABCD']]);

		$ao = Address::findFTN('100:1/0@a');
		$this->assertCount(185-36,$ao->children);
	}

	// If we also have session details for an Hub, then there are less RC nodes
	public function test_rc_hub_session_children()
	{
		$this->session_rc();

		$ao = Address::findFTN('100:10/20@a');
		$ao->system->sessions()->attach([$ao->zone_id=>['sespass'=>'ABCD']]);

		$ao = Address::findFTN('100:1/0@a');
		$this->assertCount(185-6,$ao->children);

		$ao = Address::findFTN('100:10/22@a');
		$this->assertEquals('100:10/20.0@a',$ao->parent()->ftn);
	}
	// If we also have session details for an Hub, then there are less RC nodes
	public function test_rc_hub_session_child()
	{
		$this->session_hub();

		$ao = Address::findFTN('100:10/22@a');
		$this->assertEquals('100:10/20.0@a',$ao->parent()->ftn);
	}
}