<?php

namespace Database\Seeders;

/**
 * Our testing heirarchy.
 *
 */

use Carbon\Carbon;
use Illuminate\Database\Seeder;
use Illuminate\Support\Facades\DB;

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

class TestNodeHierarchy extends Seeder
{
	public const DEBUG = TRUE;

	/**
	 * Run the database seeds.
	 *
	 * @return void
	 * @throws \Exception
	 */
    public function run()
    {
		foreach (['a','b','c','d','e','f'] as $domain) {
			DB::table('domains')
				->insert([
					'name'=>$domain,
					'active'=>TRUE,
					'public'=>TRUE,
					'created_at'=>Carbon::now(),
					'updated_at'=>Carbon::now(),
				]);

			$do = Domain::where('name',$domain)->sole();
			$this->hierarchy($do,100);
			$this->hierarchy($do,101);
		}

		// Configure my addresses
		$so = Setup::findOrFail(config('app.id'));

		// ZC 100:0/0@a
		$ao = Address::findFTN('100:0/0@a');
		$ao->system_id = $so->system_id;
		$ao->save();

		// RC 100:1/0@b
		$ao = Address::findFTN('100:1/0@b');
		$ao->system_id = $so->system_id;
		$ao->save();

		// NC 100:20/0@c
		$ao = Address::findFTN('100:20/0@c');
		$ao->system_id = $so->system_id;
		$ao->save();

		// HUB 100:30/100@d
		$ao = Address::findFTN('100:30/100@d');
		$ao->system_id = $so->system_id;
		$ao->save();

		// NODE 100:40/101@e
		$ao = Address::findFTN('100:40/101@e');
		$ao->system_id = $so->system_id;
		$ao->save();

		// POINT 100:50/101.3277@f
		$ao = Address::createFTN('100:50/101.3277@f',$so->system);

		$so->system->name = 'Clearing Houz TEST';
		$so->system->address = 'localhost';
		$so->system->save();

		// Add file area
		DB::table('fileareas')
			->insert([
				'name'=>'FILE_AREA',
				'description'=>'Testing File Area',
				'active'=>TRUE,
				'show'=>TRUE,
				'notes'=>'File area for testing',
				'domain_id'=>$ao->zone->domain_id,
				'security'=>1,
				'created_at'=>Carbon::now(),
				'updated_at'=>Carbon::now(),
			]);
    }

    private function hierarchy(Domain $domain,int $zoneid)
	{
		$levels = [1,2,3,4,5];
		$hubnodes = [-2,-1,+1,+2,+3];

		$so = $this->system(sprintf('ZC %s-%s',$domain->name,$zoneid));
		DB::table('zones')
			->insert([
				'zone_id'=>$zoneid,
				'active'=>TRUE,
				'default'=>$domain->name === 'a',
				'notes'=>sprintf('Zone: %03d:0/0.0@%s',$zoneid,$domain->name),
				'domain_id'=>$domain->id,
				'system_id'=>$so->id,
				'created_at'=>Carbon::now(),
				'updated_at'=>Carbon::now(),
			]);

		$zo = Zone::where('zone_id',$zoneid)->where('domain_id',$domain->id)->sole();

		if (self::DEBUG)
			printf("- ZC %d:%d/%d.%d@%s\n",$zo->zone_id,0,0,0,$domain->name);

		$region_id = 0;
		// ZC Address
		DB::table('addresses')
			->insert([
				'zone_id'=>$zo->id,
				'active'=>TRUE,
				'region_id'=>$region_id,
				'host_id'=>$region_id,
				'node_id'=>0,
				'point_id'=>0,
				'system_id'=>$so->id,
				'created_at'=>Carbon::now(),
				'updated_at'=>Carbon::now(),
			]);

		// ZC Nodes
		foreach ($hubnodes as $hnid) {
			$host_id = $region_id*100+$hnid+3;

			if (self::DEBUG)
				printf("  - NODE %d:%d/%d.%d@%s\n",$zo->zone_id,$region_id,$host_id,0,$domain->name);

			$so = $this->system(sprintf('ZC Node 0/%d',$host_id));
			DB::table('addresses')
				->insert([
					'zone_id'=>$zo->id,
					'active'=>TRUE,
					'region_id'=>$region_id,
					'host_id'=>$region_id,
					'node_id'=>$host_id,
					'point_id'=>0,
					'system_id'=>$so->id,
					'created_at'=>Carbon::now(),
					'updated_at'=>Carbon::now(),
				]);
		}

		// RC
		foreach ($levels as $region_id) {
			if (self::DEBUG)
				printf("  - RC %d:%d/%d.%d@%s\n",$zo->zone_id,$region_id,0,0,$domain->name);

			$so = $this->system(sprintf('RC %03d:%03d/%03d.0@%s',$zoneid,$region_id,0,$domain->name));
			DB::table('addresses')
				->insert([
					'zone_id'=>$zo->id,
					'active'=>TRUE,
					'region_id'=>$region_id,
					'host_id'=>$region_id,
					'node_id'=>0,
					'point_id'=>0,
					'system_id'=>$so->id,
					'created_at'=>Carbon::now(),
					'updated_at'=>Carbon::now(),
				]);

			// RC Nodes
			foreach ($hubnodes as $hnid) {
				$host_id = $hnid+3;

				if (self::DEBUG)
					printf("    - NODE %d:%d/%d.%d@%s\n",$zo->zone_id,$region_id,$host_id,0,$domain->name);

				$so = $this->system(sprintf('RC Node %d/%d',$region_id,$host_id));
				DB::table('addresses')
					->insert([
						'zone_id'=>$zo->id,
						'active'=>TRUE,
						'region_id'=>$region_id,
						'host_id'=>$region_id,
						'node_id'=>$host_id,
						'point_id'=>0,
						'system_id'=>$so->id,
						'created_at'=>Carbon::now(),
						'updated_at'=>Carbon::now(),
					]);
			}

			// NC
			foreach ($levels as $ncid) {
				$net_id = $region_id*10+$ncid-1;
				if (self::DEBUG)
					printf("    - NC %d:%d/%d.%d@%s\n",$zo->zone_id,$net_id,0,0,$domain->name);

				$so = $this->system(sprintf('NC %d:%d/0 (R%d)',$zo->zone_id,$net_id,$region_id));
				DB::table('addresses')
					->insert([
						'zone_id'=>$zo->id,
						'active'=>TRUE,
						'region_id'=>$region_id,
						'host_id'=>$net_id,
						'node_id'=>0,
						'point_id'=>0,
						'system_id'=>$so->id,
						'created_at'=>Carbon::now(),
						'updated_at'=>Carbon::now(),
					]);

				// NC Nodes
				foreach ($hubnodes as $hnid) {
					$host_id = $hnid+3;

					if (self::DEBUG)
						printf("      - NODE %d:%d/%d.%d@%s\n",$zo->zone_id,$net_id,$host_id,0,$domain->name);

					$so = $this->system(sprintf('NC Node %d/%d (R%d)',$net_id,$host_id,$region_id));
					DB::table('addresses')
						->insert([
							'zone_id'=>$zo->id,
							'active'=>TRUE,
							'region_id'=>$region_id,
							'host_id'=>$net_id,
							'node_id'=>$host_id,
							'point_id'=>0,
							'system_id'=>$so->id,
							'created_at'=>Carbon::now(),
							'updated_at'=>Carbon::now(),
						]);
				}

				// Hubs
				foreach ($levels as $hbid) {
					$host_id = $hbid*100;

					if (self::DEBUG)
						printf("      - HUB %d:%d/%d.%d@%s\n",$zo->zone_id,$net_id,$host_id,0,$domain->name);

					$so = $this->system(sprintf('HUB %d/%d (R%d)',$net_id,$host_id,$region_id));
					$hub = new Address;
					$hub->zone_id = $zo->id;
					$hub->active = TRUE;
					$hub->region_id = $region_id;
					$hub->host_id = $net_id;
					$hub->node_id = $host_id;
					$hub->point_id = 0;
					$hub->system_id = $so->id;
					$hub->created_at = Carbon::now();
					$hub->updated_at = Carbon::now();
					$hub->save();

					// HUB Nodes
					foreach ($hubnodes as $nid) {
						$host_id = $hub->node_id+$nid;

						if (self::DEBUG)
							printf("        - NODE %d:%d/%d.%d@%s\n",$zo->zone_id,$net_id,$host_id,0,$domain->name);

						$so = $this->system(sprintf('Hub Node %d/%d (R%d/H%d)',$net_id,$host_id,$region_id,$hub->node_id));
						DB::table('addresses')
							->insert([
								'zone_id'=>$zo->id,
								'active'=>TRUE,
								'region_id'=>$region_id,
								'host_id'=>$net_id,
								'node_id'=>$host_id,
								'point_id'=>0,
								'system_id'=>$so->id,
								'hub_id'=>$hub->id,
								'created_at'=>Carbon::now(),
								'updated_at'=>Carbon::now(),
							]);

						foreach ($hubnodes as $nid) {
							$point_id = $nid+3;

							if (self::DEBUG)
								printf("          - POINT %d:%d/%d.%d@%s\n",$zo->zone_id,$net_id,$host_id,$point_id,$domain->name);

							$so = $this->system(sprintf('Node Point %d/%d.%d (R%d/H%d)',$net_id,$host_id,$point_id,$region_id,$hub->node_id));
							DB::table('addresses')
								->insert([
									'zone_id'=>$zo->id,
									'active'=>TRUE,
									'region_id'=>$region_id,
									'host_id'=>$net_id,
									'node_id'=>$host_id,
									'point_id'=>$point_id,
									'system_id'=>$so->id,
									'created_at'=>Carbon::now(),
									'updated_at'=>Carbon::now(),
								]);
						}
					}
				}
			}
		}
	}

	private function system(string $name): System
	{
		$o = new System;
		$o->name = $name;
		$o->sysop = 'Sysop:'.$name;
		$o->location = 'Location:'.$name;
		$o->active = TRUE;
		$o->created_at = Carbon::now();
		$o->updated_at = Carbon::now();
		$o->address = 'myhostname';
		$o->save();

		return $o;
	}
}