<?php

namespace App\Console\Commands;

use App\Jobs\Packages\SendEventPackageGalleryExpired;
use App\Jobs\Packages\SendEventPackageGalleryWarning;
use App\Jobs\Packages\SendEventPackageGuestLimitNotification;
use App\Jobs\Packages\SendEventPackageGuestThresholdWarning;
use App\Jobs\Packages\SendEventPackagePhotoLimitNotification;
use App\Jobs\Packages\SendEventPackagePhotoThresholdWarning;
use App\Jobs\Packages\SendTenantPackageEventLimitNotification;
use App\Jobs\Packages\SendTenantPackageEventThresholdWarning;
use App\Jobs\Packages\SendTenantPackageExpiredNotification;
use App\Jobs\Packages\SendTenantPackageExpiringNotification;
use App\Models\TenantNotificationLog;
use Illuminate\Console\Command;
use Illuminate\Support\Arr;

class RetryTenantNotification extends Command
{
    protected $signature = 'tenant:notifications:retry {log_id?} {--tenant=} {--status=failed}';

    protected $description = 'Retry tenant package limit notifications based on stored notification logs.';

    public function handle(): int
    {
        $query = TenantNotificationLog::query();

        if ($logId = $this->argument('log_id')) {
            $query->whereKey($logId);
        }

        if ($tenantId = $this->option('tenant')) {
            $query->where('tenant_id', $tenantId);
        }

        if ($status = $this->option('status')) {
            $query->where('status', $status);
        }

        $logs = $query->orderBy('id')->get();

        if ($logs->isEmpty()) {
            $this->warn('No notification logs matched the given filters.');

            return self::SUCCESS;
        }

        foreach ($logs as $log) {
            $dispatched = $this->dispatchForLog($log);

            if ($dispatched) {
                $log->forceFill([
                    'status' => 'queued',
                    'failed_at' => null,
                    'failure_reason' => null,
                ])->save();

                $this->info("Queued retry for log #{$log->id} ({$log->type})");
            } else {
                $this->warn("Skipped log #{$log->id} ({$log->type}) – missing context");
            }
        }

        return self::SUCCESS;
    }

    private function dispatchForLog(TenantNotificationLog $log): bool
    {
        $context = $log->context ?? [];

        return match ($log->type) {
            'photo_threshold' => $this->dispatchPhotoThreshold($context),
            'photo_limit' => $this->dispatchPhotoLimit($context),
            'guest_threshold' => $this->dispatchGuestThreshold($context),
            'guest_limit' => $this->dispatchGuestLimit($context),
            'gallery_warning' => $this->dispatchGalleryWarning($context),
            'gallery_expired' => $this->dispatchGalleryExpired($context),
            'event_threshold' => $this->dispatchEventThreshold($context),
            'event_limit' => $this->dispatchEventLimit($context),
            'package_expiring' => $this->dispatchPackageExpiring($context),
            'package_expired' => $this->dispatchPackageExpired($context),
            default => false,
        };
    }

    private function dispatchPhotoThreshold(array $context): bool
    {
        $eventPackageId = Arr::get($context, 'event_package_id');
        $threshold = Arr::get($context, 'threshold');
        $limit = Arr::get($context, 'limit');
        $used = Arr::get($context, 'used');

        if ($eventPackageId === null || $threshold === null || $limit === null || $used === null) {
            return false;
        }

        SendEventPackagePhotoThresholdWarning::dispatch($eventPackageId, (float) $threshold, (int) $limit, (int) $used);

        return true;
    }

    private function dispatchPhotoLimit(array $context): bool
    {
        $eventPackageId = Arr::get($context, 'event_package_id');
        $limit = Arr::get($context, 'limit');

        if ($eventPackageId === null || $limit === null) {
            return false;
        }

        SendEventPackagePhotoLimitNotification::dispatch($eventPackageId, (int) $limit);

        return true;
    }

    private function dispatchGuestThreshold(array $context): bool
    {
        $eventPackageId = Arr::get($context, 'event_package_id');
        $threshold = Arr::get($context, 'threshold');
        $limit = Arr::get($context, 'limit');
        $used = Arr::get($context, 'used');

        if ($eventPackageId === null || $threshold === null || $limit === null || $used === null) {
            return false;
        }

        SendEventPackageGuestThresholdWarning::dispatch($eventPackageId, (float) $threshold, (int) $limit, (int) $used);

        return true;
    }

    private function dispatchGuestLimit(array $context): bool
    {
        $eventPackageId = Arr::get($context, 'event_package_id');
        $limit = Arr::get($context, 'limit');

        if ($eventPackageId === null || $limit === null) {
            return false;
        }

        SendEventPackageGuestLimitNotification::dispatch($eventPackageId, (int) $limit);

        return true;
    }

    private function dispatchGalleryWarning(array $context): bool
    {
        $eventPackageId = Arr::get($context, 'event_package_id');
        $days = Arr::get($context, 'days_remaining');

        if ($eventPackageId === null || $days === null) {
            return false;
        }

        SendEventPackageGalleryWarning::dispatch($eventPackageId, (int) $days);

        return true;
    }

    private function dispatchGalleryExpired(array $context): bool
    {
        $eventPackageId = Arr::get($context, 'event_package_id');

        if ($eventPackageId === null) {
            return false;
        }

        SendEventPackageGalleryExpired::dispatch($eventPackageId);

        return true;
    }

    private function dispatchEventThreshold(array $context): bool
    {
        $tenantPackageId = Arr::get($context, 'tenant_package_id');
        $threshold = Arr::get($context, 'threshold');
        $limit = Arr::get($context, 'limit');
        $used = Arr::get($context, 'used');

        if ($tenantPackageId === null || $threshold === null || $limit === null || $used === null) {
            return false;
        }

        SendTenantPackageEventThresholdWarning::dispatch($tenantPackageId, (float) $threshold, (int) $limit, (int) $used);

        return true;
    }

    private function dispatchEventLimit(array $context): bool
    {
        $tenantPackageId = Arr::get($context, 'tenant_package_id');
        $limit = Arr::get($context, 'limit');

        if ($tenantPackageId === null || $limit === null) {
            return false;
        }

        SendTenantPackageEventLimitNotification::dispatch($tenantPackageId, (int) $limit);

        return true;
    }

    private function dispatchPackageExpiring(array $context): bool
    {
        $tenantPackageId = Arr::get($context, 'tenant_package_id');
        $days = Arr::get($context, 'days_remaining');

        if ($tenantPackageId === null || $days === null) {
            return false;
        }

        SendTenantPackageExpiringNotification::dispatch($tenantPackageId, (int) $days);

        return true;
    }

    private function dispatchPackageExpired(array $context): bool
    {
        $tenantPackageId = Arr::get($context, 'tenant_package_id');

        if ($tenantPackageId === null) {
            return false;
        }

        SendTenantPackageExpiredNotification::dispatch($tenantPackageId);

        return true;
    }
}
