<?php

namespace App\Classes\File;

use Carbon\Carbon;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Log;
use Illuminate\Support\Facades\Storage;

use App\Classes\Node;
use App\Models\File as FileModel;

final class File extends Send
{
	private const LOGKEY = 'ISF';

	/** @var mixed Our open file descriptor */
	private mixed $fd;

	/**
	 * @throws \Exception
	 */
	public function __construct(FileModel $file,int $type)
	{
		parent::__construct();

		$this->f = $file;
		$this->ftype = ((($type&0xff)<<8)|self::IS_FILE);
	}

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

			case 'full_name':
			case 'nameas':
				return $this->f->name;

			case 'mtime':
				return $this->f->datetime->timestamp;

			case 'name':
				return $this->f->{$key};

			case 'type':
				return ($this->ftype&0xff00)>>8;

			default:
				return parent::__get($key);
		}
	}

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

			if (($this->type === Send::T_FILE)
				&& ($x=$this->dbids)->count()
				&& $node->aka_remote_authed->count())
				DB::table('file_seenby')
					->whereIn('file_id',$x)
					->whereIn('address_id',$node->aka_remote_authed->pluck('id'))
					->update([
						'sent_at'=>Carbon::now(),
					]);
		}

		fclose($this->fd);
	}

	public function feof(): bool
	{
		return feof($this->fd);
	}

	/**
	 * Open a file for sending
	 *
	 * @param string $compress The compression method that will be used (not implemented)
	 * @return bool
	 */
	public function open(string $compress=''): bool
	{
		$this->size = $this->f->size;

		// If sending file is a File::class, then our file is s3
		$this->fd = ($this->nameas && $this->f instanceof FileModel)
			? Storage::readStream($this->f->rel_name)
			: fopen($this->full_name,'rb');

		if (! $this->fd) {
			Log::error(sprintf('%s:! Unable to open file [%s] for reading',self::LOGKEY,$this->full_name));

			return FALSE;
		}

		Log::info(sprintf('%s:= File [%s] opened with size [%d]',self::LOGKEY,$this->full_name,$this->size));

		return TRUE;
	}

	public function read(int $length): string
	{
		return fread($this->fd,$length);
	}

	public function seek(int $pos): bool
	{
		return (fseek($this->fd,$pos,SEEK_SET) === 0);
	}
}