<?php

namespace App\Models;

use Exception;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\BelongsToMany;

use App\Traits\ScopeActive;

class Node extends Model
{
	use ScopeActive;

	protected $casts = [
		'is_zc'=>'boolean',
		'is_rc'=>'boolean',
		'is_hub'=>'boolean',
		'is_host'=>'boolean',
	];

	protected $fillable = ['zone_id','host_id','node_id','point_id'];

	/* SCOPES */

	public function scopeHost()
	{
		// @todo
	}

	/* RELATIONS */

	/**
	 * Node nodelist flags
	 *
	 * @return BelongsToMany
	 */
	public function flags()
	{
		return $this->belongsToMany(Flag::class);
	}

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

	/* ATTRIBUTES */

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

	/**
	 * Get this nodes uplink
	 */
	public function getUplinkAttribute()
	{
		// @todo Need to work this out properly
		return static::where('zone_id','10')->where('host_id',1)->where('node_id',0)->where('point_id',0)->first();
	}

	/* 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 = [];

		// @todo domain can have more chars.
		if (! preg_match('#^([0-9]+):([0-9]+)/([0-9]+)(.([0-9]+))?(@([a-z]{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] > 0xffff))
				throw new Exception('Invalid FTN: '.$ftn);
		}
		if (isset($matches[5]) AND $matches[5] > 0xffff)
			throw new Exception('Invalid FTN: '.$ftn);

		return (new self)->active()
			->select('nodes.*')
			->where('zones.zone_id',$matches[1])
			->where(function($query) use ($matches) {
				$query->where('hub_id',$matches[2])
					->orWhere('host_id',$matches[2]);
			})
			->join('zones',['zones.id'=>'nodes.zone_id'])
			->join('domains',['domains.id'=>'zones.domain_id'])
			->where('zones.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();
	}

	public function hasFlag($relation,$model): bool
	{
		return (bool) $this->{$relation}()
			->wherePivot($model->getForeignKey(),$model->{$model->getKeyName()})
			->count();
	}
}