<?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,Echoarea,Echomail};
use App\Notifications\Netmails\Areafix\Scan;

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

	private const LOGKEY = 'JAR';

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

	/**
	 * Create a new job instance.
	 */
	public function __construct(Address $ao,Echoarea $eao,int $days=30,bool $rescan=FALSE)
	{
		$this->ao = $ao->withoutRelations();
		$this->eao = $eao->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->eao->name,$this->days);

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

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

					return TRUE;

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

					return TRUE;

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

					return TRUE;
				}

				return FALSE;
			})
		];
	}

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

		$earliest = NULL;
		$latest = NULL;

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

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

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

				Log::debug(sprintf('Exported [%d] MSG (%s) dated (%s) to [%s]',$eo->id,$eo->msgid ?: '*NO MSGID*',$eo->datetime->format('Y-m-d H:i:s'),$this->ao->ftn3d));

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

				if ($export) {
					// Echomail 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] MSG (%s) dated (%s) already queued for [%s]',$eo->id,$eo->msgid ?: '*NO MSGID*',$eo->datetime->format('Y-m-d H:i:s'),$this->ao->ftn3d));

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

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

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

						Log::debug(sprintf('Re-exported [%d] MSG (%s) dated (%s) to [%s]',$eo->id,$eo->msgid ?: '*NO MSGID*',$eo->datetime,$this->ao->ftn3d));

					} else {
						$s++;
						Log::debug(sprintf('Not resending previously sent message [%d], MSGID (%s) - sent in Pkt [%s] on [%s]',
							$eo->id,
							$eo->msgid ?: '* NO MSGID*',
							$export->pivot->sent_pkt ?: '-',
							$export->pivot->sent_at ?: '-',
						));
					}

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

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

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

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

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

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