<?php

namespace App\Classes\File\Send;

use Carbon\Carbon;

use App\Classes\File\Send;
use App\Classes\Node;
use App\Models\Address;
use App\Models\Dynamic as Model;
use App\Classes\Dynamic as Item;

/**
 * Dynamic files that are sent to systems during a mailer session
 */
final class Dynamic extends Send
{
	private const LOGKEY = 'FSD';

	/** @var int Our internal position counter */
	private int $readpos = 0;
	private string $buffer;
	private Item $item;
	private Carbon $sent;

	/**
	 * @throws \Exception
	 */
	public function __construct(private Model $do,Address $ao,int $type)
	{
		parent::__construct();

		$this->ftype = ((($type&0xff)<<8)|self::IS_FILE);
		$this->item = new $this->do->model($ao,$this->do->arguments);
		$this->sent = Carbon::now();
	}

	public function __get($key) {
		switch ($key) {
			case 'dbids':
				return collect([$this->do->id]);

			case 'nameas':
				return $this->item->getName();

			case 'mtime':
				return $this->sent->timestamp;

			case 'size':
				return strlen($this->buffer);

			default:
				return NULL;
		}
	}

	public function close(bool $successful,Node $node): void
	{
		if ($successful) {
			$this->complete = TRUE;

			$next_at = $this->do->next_at
				->startOfDay()
				->addHours($this->do->start_time->hour)
				->addMinutes($this->do->start_time->minute);

			switch ($this->do->frequency) {
				case 'ONCE':
					$this->do->active = FALSE;

					break;

				case 'DAILY':
					$this->do->next_at = $next_at
						->addDay();

					break;

				case 'WEEKLY':
					$this->do->next_at = $next_at
						->addWeek();

					break;

				case 'MONTHLY':
					$this->do->next_at = $next_at
						->addMonth();

					break;

				default:
					throw new \Exception(sprintf('%s:! Unknown frequency [%s] for [%d]',self::LOGKEY,$this->do->frequency,$this->do->id));
			}

			$this->do->save();
		}
	}

	public function feof(): bool
	{
		return ($this->readpos === $this->size);
	}

	public function open(string $compress=''): bool
	{
		$this->buffer = (string)$this->item;

		return TRUE;
	}

	public function read(int $length): string
	{
		$result = substr($this->buffer,$this->readpos,$length);
		$this->readpos += strlen($result);

		return $result;
	}

	public function seek(int $pos): bool
	{
		$this->readpos = ($pos < $this->size) ? $pos : $this->size;
		return TRUE;
	}
}