<?php

/**
 * Common Attributes used by message packets (and thus their Models)
 */
namespace App\Traits;

use Carbon\Carbon;
use Illuminate\Support\Collection;
use Illuminate\Support\Facades\Log;
use Illuminate\Support\MessageBag;

use App\Classes\FTN\Message;
use App\Models\{Address,Echomail,Origin,Tagline,Tearline};

trait MessageAttributes
{
	// Items we need to set when creating()
	public Collection $set;
	// Validation Errors
	public ?MessageBag $errors = NULL;

	public function __construct()
	{
		parent::__construct();

		// Init
		$this->set = collect();
	}

	/* RELATIONS */

	public function fftn()
	{
		return $this
			->belongsTo(Address::class)
			->withTrashed();
	}

	public function origin()
	{
		return $this->belongsTo(Origin::class);
	}

	public function tagline()
	{
		return $this->belongsTo(Tagline::class);
	}

	public function tearline()
	{
		return $this->belongsTo(Tearline::class);
	}

	/* ATTRIBUTES */

	public function getContentAttribute(): string
	{
		return ($this->msg_src) ? $this->msg_src : $this->rebuildMessage();
	}

	/**
	 * This is used to build our data in a timezone date, so that when exported, we include the right TZUTC
	 *
	 * @return Carbon
	 */
	public function getDateAttribute(): Carbon
	{
		// Datetime is in utc, and tzoffset describes what that local time is
		return $this->datetime->clone()->utcOffset($this->tzoffset);
	}

	public function getOriginAttribute(string $val=NULL): ?string
	{
		if (($x=$this->getRelationValue('origin')) && $x->value)
			return $x->complete($this->fftn);

		if (($this->set->has('set_origin')) || ($val))
			return sprintf(' * Origin: %s',$this->set->get('set_origin',$val));

		return NULL;
	}

	public function getTaglineAttribute(string $val=NULL): ?string
	{
		if (($x=$this->getRelationValue('tagline')) && $x->value)
			return $x->complete();

		if (($this->set->has('set_tagline')) || ($val))
			return sprintf('... %s',$this->set->get('set_tagline',$val));

		return NULL;
	}

	public function getTearlineAttribute(string $val=NULL): ?string
	{
		if (($x=$this->getRelationValue('tearline')) && $x->value)
			return $x->complete();

		if (($this->set->has('set_tearline')) || ($val))
			return sprintf('--- %s',$this->set->get('set_tearline',$val));

		return NULL;
	}

	/* METHODS */

	/**
	 * Return an array of flag descriptions
	 *
	 * @return Collection
	 *
	 * http://ftsc.org/docs/fsc-0001.000
	 *       AttributeWord   bit       meaning
	 * ---       --------------------
	 * 0  +    Private
	 * 1  + s  Crash
	 * 2       Recd
	 * 3       Sent
	 * 4  +    FileAttached
	 * 5       InTransit
	 * 6       Orphan
	 * 7       KillSent
	 * 8       Local
	 * 9    s  HoldForPickup
	 * 10  +    unused
	 * 11    s  FileRequest
	 * 12  + s  ReturnReceiptRequest
	 * 13  + s  IsReturnReceipt
	 * 14  + s  AuditRequest
	 * 15    s  FileUpdateReq
	 *
	 * s - this bit is supported by SEAdog only
	 * + - this bit is not zeroed before packeting
	 */
	public function flags(): Collection
	{
		return collect([
			'private' => $this->isFlagSet(Message::FLAG_PRIVATE),
			'crash' => $this->isFlagSet(Message::FLAG_CRASH),
			'recd' => $this->isFlagSet(Message::FLAG_RECD),
			'sent' => $this->isFlagSet(Message::FLAG_SENT),
			'fileattach' => $this->isFlagSet(Message::FLAG_FILEATTACH),
			'intransit' => $this->isFlagSet(Message::FLAG_INTRANSIT),
			'orphan' => $this->isFlagSet(Message::FLAG_ORPHAN),
			'killsent' => $this->isFlagSet(Message::FLAG_KILLSENT),
			'local' => $this->isFlagSet(Message::FLAG_LOCAL),
			'hold' => $this->isFlagSet(Message::FLAG_HOLD),
			'unused-10' => $this->isFlagSet(Message::FLAG_UNUSED_10),
			'filereq' => $this->isFlagSet(Message::FLAG_FREQ),
			'receipt-req' => $this->isFlagSet(Message::FLAG_RETRECEIPT),
			'receipt' => $this->isFlagSet(Message::FLAG_ISRETRECEIPT),
			'audit' => $this->isFlagSet(Message::FLAG_AUDITREQ),
			'fileupdate' => $this->isFlagSet(Message::FLAG_FILEUPDATEREQ),
			'pktpasswd' => $this->isFlagSet(Message::FLAG_PKTPASSWD),
		])->filter();
	}

	public function isFlagSet($flag): bool
	{
		return ($this->flags & $flag);
	}

	/**
	 * Return this model as a packet
	 */
	public function packet(Address $ao): Message
	{
		Log::debug(sprintf('%s:+ Bundling [%s] for [%s]',self::LOGKEY,$this->id,$ao->ftn3d),['type'=>get_class($this)]);

		// For echomail, our tftn is this address
		if ($this instanceof Echomail)
			$this->tftn = $ao;

		// @todo Dont bundle mail to nodes that have been disabled, or addresses that have been deleted
		return Message::packMessage($this);
	}

	public function rebuildMessage(): string
	{
		// If we have a msg_src attribute, we'll use that
		$result = $this->msg."\r\r";

		if ($x=$this->tagline)
			$result .= sprintf("%s\r",$x);

		if ($x=$this->tearline)
			$result .= sprintf("%s\r",$x);

		if ($x=$this->origin)
			$result .= sprintf("%s",$x);

		return rtrim($result,"\r");
	}

	/**
	 * Return our path in order
	 *
	 * @param string $display
	 * @param int|NULL $start
	 * @return Collection
	 */
	public function pathorder(string $display='ftn2d',int $start=NULL): Collection
	{
		$result = collect();

		if ($x=$this->path->firstWhere('pivot.parent_id',$start)) {
			$result->push($x->$display);
			$result->push($this->pathorder($display,$x->pivot->id));
		}

		return $result->flatten()->filter();
	}
}