<?php

namespace App\Jobs;

use Carbon\Carbon;
use Illuminate\Bus\Queueable;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Foundation\Bus\Dispatchable;
use Illuminate\Queue\InteractsWithQueue;
use Illuminate\Queue\Middleware\Skip;
use Illuminate\Queue\SerializesModels;
use Illuminate\Support\Facades\Log;
use Illuminate\Support\Facades\Notification;

use App\Models\{Address,Filearea,File};
use App\Notifications\Netmails\Filefix\Scan;

class FilefixRescan implements ShouldQueue
{
	use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;

	private const LOGKEY = 'JAR';

	private Address $ao;		// System address
	private Filearea $fao;		// Domain we are processing
	private int $days;
	private bool $rescan;

	/**
	 * Create a new job instance.
	 */
	public function __construct(Address $ao,Filearea $fao,int $days=30,bool $rescan=FALSE)
	{
		$this->ao = $ao->withoutRelations();
		$this->fao = $fao->withoutRelations();
		$this->days = $days;
		$this->rescan = $rescan;
	}

	public function __get(string $key): mixed
	{
		switch ($key) {
			case 'jobname':
				return sprintf('%s %s (%d)',$this->ao->ftn,$this->fao->name,$this->days);

			default:
				$this->fail('Unkown key:'.$key);
				return NULL;
		}
	}

	public function middleware(): array
	{
		return [
			Skip::when(function(): bool {
				if ($this->fao->domain_id !== $this->ao->zone->domain_id) {
					Log::error(sprintf('%s:! File area [%s] is not in domain [%s] for FTN [%s]',self::LOGKEY,$this->fao->name,$this->ao->zone->domain->name,$this->ao->ftn));

					return TRUE;

				// Check that the user is subscribed
				} elseif (! $this->ao->fileareas->contains($this->fao->id)) {
					Log::error(sprintf('%s:! FTN [%s] is not subscribed to [%s]',self::LOGKEY,$this->ao->ftn,$this->fao->name));

					return TRUE;

				// Check that an FTN can read the area
				} elseif (! $this->fao->can_read($this->ao->security)) {
					Log::error(sprintf('%s:! FTN [%s] doesnt have permission to receive [%s]',self::LOGKEY,$this->ao->ftn,$this->fao->name));

					return TRUE;
				}

				return FALSE;
			})
		];
	}

	public function handle(): void
	{
		$c = 0;
		$s = 0;

		$earliest = NULL;
		$latest = NULL;

		foreach (File::select(['id','datetime','name'])
			->where('filearea_id',$this->fao->id)
			->where('datetime','>=',
				Carbon::now()
					->subDays($this->days)
					->startOfDay()
			)
			->orderBy('datetime')
			->cursor() as $fo)
		{
			// File hasnt been exported before
			if (! $fo->seenby->where('address_id',$this->ao->id)->count()) {
				$fo->seenby()->attach($this->ao->id,['export_at'=>Carbon::now()]);
				$c++;

				if (($fo->datetime < $earliest) || (! $earliest))
					$earliest = $fo->datetime;

				if (($latest < $fo->datetime) || (! $latest))
					$latest = $fo->datetime;

				Log::debug(sprintf('Exported [%d] FILE (%s) dated (%s) to [%s]',$fo->id,$fo->name,$fo->datetime->format('Y-m-d H:i:s'),$this->ao->ftn3d));

			} else {
				$export = $fo->seenby->where('id',$this->ao->id)->pop();

				if ($export) {
					// File is pending export
					if ($export->pivot->export_at && is_null($export->pivot->sent_at) && is_null($export->pivot->sent_pkt)) {
						$s++;
						Log::debug(sprintf('Not exporting [%d] FILE (%s) dated (%s) already queued for [%s]',$fo->id,$fo->name,$fo->datetime->format('Y-m-d H:i:s'),$this->ao->ftn3d));

					// File has been exported
					} elseif ($this->rescan) {
						$fo->seenby()->updateExistingPivot($this->ao,['export_at'=>Carbon::now(),'sent_at'=>NULL]);
						$c++;

						if (($fo->datetime < $earliest) || (! $earliest))
							$earliest = $fo->datetime;

						if (($latest < $fo->datetime) || (! $latest))
							$latest = $fo->datetime;

						Log::debug(sprintf('Re-exported [%d] FILE (%s) dated (%s) to [%s]',$fo->id,$fo->name,$fo->datetime,$this->ao->ftn3d));

					} else {
						$s++;
						Log::debug(sprintf('Not resending previously sent file [%d], FILE (%s) - sent on [%s]',
							$fo->id,
							$fo->name,
							$export->pivot->sent_at ?: '-',
						));
					}

				// File has not been exported
				} else {
					$fo->seenby()->attach($this->ao,['export_at'=>Carbon::now(),'sent_at'=>NULL]);
					$c++;

					if (($fo->datetime < $earliest) || (! $earliest))
						$earliest = $fo->datetime;

					if (($latest < $fo->datetime) || (! $latest))
						$latest = $fo->datetime;

					Log::debug(sprintf('Exported [%d] to [%s]',$fo->id,$this->ao->ftn3d));
				}
			}
		}

		Notification::route('netmail',$this->ao)
			->notify(new Scan(collect([
				'area'=>$this->fao->name,
				'queued'=>$c,
				'skipped'=>$s,
				'earliest'=>$earliest,
				'latest'=>$latest,
			])));

		Log::info(sprintf('%s:= Queued [%d], Skipped [%d] files for [%s] in [%s]',self::LOGKEY,$c,$s,$this->ao->ftn,$this->fao->name));
	}
}