<?php

namespace App\Services\Integrations;

use App\Jobs\ProcessRevenueCatWebhook;
use App\Models\IntegrationWebhookEvent;
use Illuminate\Support\Carbon;
use Illuminate\Support\Facades\DB;

class IntegrationHealthService
{
    /**
     * @return array<int, array<string, mixed>>
     */
    public function providers(): array
    {
        return [
            $this->buildProvider('paddle', 'Paddle', [
                'is_configured' => filled(config('paddle.webhook_secret')),
                'label' => 'Webhook secret',
            ]),
            $this->buildProvider('revenuecat', 'RevenueCat', [
                'is_configured' => filled(config('services.revenuecat.webhook')),
                'label' => 'Webhook secret',
                'queue' => config('services.revenuecat.queue', 'webhooks'),
                'job_class' => ProcessRevenueCatWebhook::class,
            ]),
        ];
    }

    /**
     * @param  array<string, mixed>  $config
     * @return array<string, mixed>
     */
    private function buildProvider(string $provider, string $label, array $config): array
    {
        $query = IntegrationWebhookEvent::query()->where('provider', $provider);
        $lastEvent = (clone $query)->orderByDesc('received_at')->first();
        $lastProcessed = (clone $query)
            ->where('status', IntegrationWebhookEvent::STATUS_PROCESSED)
            ->orderByDesc('processed_at')
            ->first();
        $lastFailed = (clone $query)
            ->where('status', IntegrationWebhookEvent::STATUS_FAILED)
            ->orderByDesc('failed_at')
            ->first();

        $pendingCount = (clone $query)
            ->where('status', IntegrationWebhookEvent::STATUS_RECEIVED)
            ->count();

        $recentFailures = (clone $query)
            ->where('status', IntegrationWebhookEvent::STATUS_FAILED)
            ->where('failed_at', '>=', now()->subDay())
            ->count();

        $queueName = $config['queue'] ?? null;
        $jobClass = $config['job_class'] ?? null;

        $queueBacklog = $this->countJobs($queueName, $jobClass);
        $failedJobs = $this->countFailedJobs($queueName, $jobClass);

        $status = $this->resolveStatus(
            (bool) ($config['is_configured'] ?? false),
            $pendingCount,
            $recentFailures,
            $failedJobs,
            $lastEvent
        );

        return [
            'provider' => $provider,
            'label' => $label,
            'config_label' => (string) ($config['label'] ?? 'Config'),
            'is_configured' => (bool) ($config['is_configured'] ?? false),
            'status' => $status,
            'status_label' => $this->statusLabel($status),
            'pending_count' => $pendingCount,
            'recent_failures' => $recentFailures,
            'queue_backlog' => $queueBacklog,
            'failed_jobs' => $failedJobs,
            'last_event' => $this->formatEvent($lastEvent),
            'last_processed' => $this->formatEvent($lastProcessed),
            'last_failed' => $this->formatEvent($lastFailed),
            'processing_lag' => $this->formatLag($lastEvent),
        ];
    }

    private function resolveStatus(
        bool $isConfigured,
        int $pendingCount,
        int $recentFailures,
        int $failedJobs,
        ?IntegrationWebhookEvent $lastEvent,
    ): string {
        if (! $isConfigured) {
            return 'unconfigured';
        }

        if ($pendingCount > 0) {
            return 'pending';
        }

        if ($recentFailures > 0 || $failedJobs > 0) {
            return 'degraded';
        }

        if (! $lastEvent) {
            return 'unknown';
        }

        return 'healthy';
    }

    private function statusLabel(string $status): string
    {
        return match ($status) {
            'healthy' => __('admin.integrations_health.status.healthy'),
            'pending' => __('admin.integrations_health.status.pending'),
            'degraded' => __('admin.integrations_health.status.degraded'),
            'unconfigured' => __('admin.integrations_health.status.unconfigured'),
            default => __('admin.integrations_health.status.unknown'),
        };
    }

    private function formatEvent(?IntegrationWebhookEvent $event): ?array
    {
        if (! $event) {
            return null;
        }

        return [
            'status' => $event->status,
            'event_type' => $event->event_type,
            'received_at' => $event->received_at,
            'processed_at' => $event->processed_at,
            'failed_at' => $event->failed_at,
            'error_message' => $event->error_message,
        ];
    }

    private function formatLag(?IntegrationWebhookEvent $event): ?array
    {
        if (! $event || ! $event->received_at) {
            return null;
        }

        $end = $event->processed_at ?? now();
        $seconds = $end->diffInSeconds($event->received_at);

        return [
            'seconds' => $seconds,
            'label' => Carbon::now()->subSeconds($seconds)->diffForHumans(null, true),
        ];
    }

    private function countJobs(?string $queueName, ?string $jobClass): int
    {
        if (! $queueName || ! $jobClass) {
            return 0;
        }

        return (int) DB::table('jobs')
            ->where('queue', $queueName)
            ->where('payload', 'like', '%'.$jobClass.'%')
            ->count();
    }

    private function countFailedJobs(?string $queueName, ?string $jobClass): int
    {
        if (! $queueName || ! $jobClass) {
            return 0;
        }

        return (int) DB::table('failed_jobs')
            ->where('queue', $queueName)
            ->where('payload', 'like', '%'.$jobClass.'%')
            ->count();
    }
}
