<?php

namespace Database\Seeders;

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

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

class NodeHierarchy extends Seeder
{
	public const DEBUG=TRUE;

    /**
     * Run the database seeds.
     *
     * @return void
     */
    public function run()
    {
		DB::table('domains')
			->insert([
				'name'=>'domain-a',
				'active'=>TRUE,
				'public'=>TRUE,
				'created_at'=>Carbon::now(),
				'updated_at'=>Carbon::now(),
			]);

		DB::table('domains')
			->insert([
				'name'=>'domain-b',
				'active'=>TRUE,
				'public'=>TRUE,
				'created_at'=>Carbon::now(),
				'updated_at'=>Carbon::now(),
			]);

		foreach (['domain-a','domain-b'] as $domain) {
			$do = Domain::where('name',$domain)->singleOrFail();
			$this->hierarchy($do,100);
			$this->hierarchy($do,101);
		}
    }

    private function hierarchy(Domain $domain,int $zoneid)
	{
		$regions = [1,2];
		//$hosts = [20,30];
		$hubs = [1000,2000];
		$nodes = [1,2,3];
		$hubnodes = [-1,+1];

		$so = $this->system('ZC '.$domain->id);
		DB::table('zones')
			->insert([
				'zone_id'=>$zoneid,
				'active'=>TRUE,
				'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)->singleOrFail();
		if (self::DEBUG)
			dump(['zo'=>$zo->zone_id,'rid'=>0,'hid'=>0,'nid'=>0]);

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

		// ZC Nodes
		foreach ($nodes as $nid) {
			if (self::DEBUG)
				dump(['rid'=>$zo->zone_id,'hid'=>$zo->zone_id,'nid'=>$nid]);

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

		if (self::DEBUG)
			dump(['end'=>'nodes top']);

		// Regions
		foreach ($regions as $rid) {
			$hostid = $rid;
			if (self::DEBUG)
				dump(['rid'=>$rid,'hid'=>$hostid,'nid'=>0]);

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

			// RC Nodes
			foreach ($nodes as $nid) {
				if (self::DEBUG)
					dump(['rid'=>$rid,'hid'=>$hostid,'nid'=>$nid]);

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

			// Hosts
			foreach ($regions as $rrid) {
				$hostid = $rid*10+$rrid-1;
				if (self::DEBUG)
					dump(['rid'=>$rid,'hid'=>$hostid,'nid'=>0]);

				$so = $this->system(sprintf('Host %03d:%03d/0.0@%s (Region %03d)',$zoneid,$hostid,$domain->name,$rid));

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

				// Nodes
				foreach ($nodes as $nid) {
					if (self::DEBUG)
						dump(['rid'=>$rid,'hid'=>$hostid,'nid'=>$nid]);

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

				// Hubs
				foreach ($hubs as $bid) {
					$so = $this->system(sprintf('Hub %03d:%03d/%03d.0@%s (Region %03d)',$zoneid,$hostid,$bid,$domain->name,$rid));
					$hub = new Address;
					$hub->zone_id = $zo->id;
					$hub->active = TRUE;
					$hub->region_id = $rid;
					$hub->host_id = $hostid;
					$hub->node_id = $bid;
					$hub->point_id = 0;
					$hub->system_id = $so->id;
					$hub->role = Address::NODE_HC;
					$hub->created_at = Carbon::now();
					$hub->updated_at = Carbon::now();
					$hub->save();

					// Nodes
					foreach ($hubnodes as $nid) {
						$nodeid = $bid+$nid;
						$so = $this->system(sprintf('Node %03d:%03d/%03d.0@%s (Region %03d) - Hub Node',$zoneid,$hostid,$nodeid,$domain->name,$rid));
						DB::table('addresses')
							->insert([
								'zone_id'=>$zo->id,
								'active'=>TRUE,
								'region_id'=>$rid,
								'host_id'=>$hostid,
								'node_id'=>$nodeid,
								'point_id'=>0,
								'system_id'=>$so->id,
								'hub_id'=>$hub->id,
								'role'=>Address::NODE_ACTIVE,
								'created_at'=>Carbon::now(),
								'updated_at'=>Carbon::now(),
							]);
					}
				}
			}
			dump(['end'=>'NODES normal']);
		}

		dump(['end'=>'heirarchy']);
	}

	private function system(string $name): System
	{
		$o = new System;
		$o->name = $name;
		$o->sysop = 'Mr Sysop of '.$name;
		$o->location = 'Some place for '.$name;
		$o->active = TRUE;
		$o->created_at = Carbon::now();
		$o->updated_at = Carbon::now();
		$o->save();

		return $o;
	}
}