<?php

namespace App\Jobs\Concerns;

use App\Models\TenantNotificationLog;
use App\Models\TenantNotificationReceipt;
use App\Models\Tenant;
use App\Services\Packages\TenantNotificationLogger;
use Illuminate\Support\Facades\Log;
use Illuminate\Support\Carbon;

trait LogsTenantNotifications
{
    protected function notificationLogger(): TenantNotificationLogger
    {
        return app(TenantNotificationLogger::class);
    }

    protected function logNotification(Tenant $tenant, array $attributes): void
    {
        $this->notificationLogger()->log($tenant, $attributes);
    }

    protected function createNotificationReceipt(
        Tenant $tenant,
        TenantNotificationLog $log,
        ?int $userId,
        ?string $recipient
    ): TenantNotificationReceipt {
        return TenantNotificationReceipt::query()->create([
            'tenant_id' => $tenant->id,
            'notification_log_id' => $log->id,
            'user_id' => $userId,
            'recipient' => $recipient,
            'status' => 'delivered',
        ]);
    }

    protected function dispatchToRecipients(
        Tenant $tenant,
        iterable $recipients,
        string $type,
        callable $callback,
        array $context = []
    ): void {
        foreach ($recipients as $recipient) {
            try {
                $callback($recipient);

                $log = $this->notificationLogger()->log($tenant, [
                    'type' => $type,
                    'channel' => 'mail',
                    'recipient' => $recipient,
                    'status' => 'sent',
                    'context' => $context,
                    'sent_at' => now(),
                ]);

                $this->createNotificationReceipt(
                    $tenant,
                    $log,
                    $tenant->user?->id,
                    $recipient
                );
            } catch (\Throwable $e) {
                Log::error('Tenant notification failed', [
                    'tenant_id' => $tenant->id,
                    'type' => $type,
                    'recipient' => $recipient,
                    'error' => $e->getMessage(),
                ]);

                $this->logNotification($tenant, [
                    'type' => $type,
                    'channel' => 'mail',
                    'recipient' => $recipient,
                    'status' => 'failed',
                    'context' => $context,
                    'failed_at' => now(),
                    'failure_reason' => $e->getMessage(),
                ]);
            }
        }
    }

    /**
     * Simple idempotency guard to avoid duplicate notifications within a cooldown window.
     *
     * @param  string[]  $dedupeKeys
     */
    protected function isDuplicateNotification(
        Tenant $tenant,
        string $type,
        array $context,
        array $dedupeKeys,
        int $cooldownMinutes = 1440
    ): bool {
        $window = Carbon::now()->subMinutes($cooldownMinutes);

        $logs = TenantNotificationLog::query()
            ->where('tenant_id', $tenant->id)
            ->where('type', $type)
            ->whereIn('status', ['sent', 'queued'])
            ->where(function ($query) use ($window) {
                $query->whereNull('created_at')
                    ->orWhere('created_at', '>=', $window)
                    ->orWhere('sent_at', '>=', $window);
            })
            ->get();

        foreach ($logs as $log) {
            $existing = is_array($log->context) ? $log->context : [];
            $matches = true;

            foreach ($dedupeKeys as $key) {
                $currentValue = $context[$key] ?? null;
                $existingValue = $existing[$key] ?? null;

                if ($currentValue != $existingValue) {
                    $matches = false;
                    break;
                }
            }

            if ($matches) {
                return true;
            }
        }

        return false;
    }
}
