<?php

namespace App\Models;

use Exception;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\SoftDeletes;

use App\Http\Controllers\DomainController;
use App\Traits\ScopeActive;

class Address extends Model
{
	use ScopeActive,SoftDeletes;

	/* SCOPES */

	public function scopeFTNOrder($query)
	{
		return $query
			->orderBy('region_id')
			->orderBy('host_id')
			->orderBy('node_id')
			->orderBy('point_id');
	}

	/* RELATIONS */

	public function system()
	{
		return $this->belongsTo(System::class);
	}

	public function zone()
	{
		return $this->belongsTo(Zone::class);
	}

	/* ATTRIBUTES */

	/**
	 * Render the node name in full 5D
	 *
	 * @return string
	 */
	public function getFTNAttribute()
	{
		return sprintf('%d:%d/%d.%d@%s',$this->zone->zone_id,$this->host_id ?: $this->region_id,$this->node_id,$this->point_id,$this->zone->domain->name);
	}

	public function getRoleAttribute($value)
	{
		switch ($value) {
			case DomainController::NODE_ZC;
				return 'Zone';
			case DomainController::NODE_RC;
				return 'Region';
			case DomainController::NODE_NC;
				return 'Host';
			case DomainController::NODE_HC;
				return 'Hub';
			case DomainController::NODE_PVT;
				return 'PVT';
			case DomainController::NODE_DOWN;
				return 'DOWN';
			case NULL:
				return 'Node';
			default:
				return '?';
		}
	}

	/* GENERAL METHODS */

	/**
	 * Find a record in the DB for a node string, eg: 10:1/1.0
	 *
	 * @param string $ftn
	 * @return Node|null
	 * @throws Exception
	 */
	public static function findFTN(string $ftn): ?self
	{
		$matches = [];

		// http://ftsc.org/docs/frl-1028.002
		if (! preg_match('#^([0-9]+):([0-9]+)/([0-9]+)(.([0-9]+))?(@([a-z0-9\-_~]{0,8}))?$#',strtolower($ftn),$matches))
			throw new Exception('Invalid FTN: '.$ftn);

		// Check our numbers are correct.
		foreach ([1,2,3] as $i) {
			if (! $matches[$i] || ($matches[$i] > DomainController::NUMBER_MAX))
				throw new Exception('Invalid FTN: '.$ftn);
		}
		if (isset($matches[5]) AND $matches[5] > DomainController::NUMBER_MAX)
			throw new Exception('Invalid FTN: '.$ftn);

		$o = (new self)->active()
			->select('addresses.*')
			->where('zones.zone_id',$matches[1])
			->where('host_id',$matches[2])
			->join('zones',['zones.id'=>'addresses.zone_id'])
			->join('domains',['domains.id'=>'zones.domain_id'])
			->where('zones.active',TRUE)
			->where('domains.active',TRUE)
			->where('addresses.active',TRUE)
			->where('node_id',$matches[3])
			->where('point_id',(isset($matches[5]) AND $matches[5]) ? $matches[5] : 0)
			->when(isset($matches[7]),function($query) use ($matches) {
				$query->where('domains.name',$matches[7]);
			})
			->when((! isset($matches[7]) OR ! $matches[7]),function($query) {
				$query->where('domains.default',TRUE);
			})
			->single();

		return ($o && $o->system->active) ? $o : NULL;
	}

	/**
	 * Retrieve the address session details/passwords
	 *
	 * @param string $type
	 * @return string|null
	 */
	public function session(string $type): ?string
	{
		static $session = NULL;

		if (is_null($session)) {
			$session = (new AddressZone)
				->where('zone_id',$this->zone_id)
				->where('system_id',$this->system_id)
				->single();
		}

		return $session ? $session->{$type} : NULL;
	}
}