<?php

namespace App\Services;

use App\Models\Notification;
use App\Jobs\SendScheduledNotification;
use Illuminate\Support\Facades\Log;
use Illuminate\Support\Facades\Artisan;

class NotificationSchedulerService
{
    /**
     * Schedule all pending notifications.
     */
    public function schedulePendingNotifications(): void
    {
        $pendingNotifications = Notification::where('status', 'scheduled')
            ->where('scheduled_at', '<=', now())
            ->where('scheduled_at', '>', now()->subMinutes(5)) // Only process notifications scheduled within last 5 minutes
            ->get();

        foreach ($pendingNotifications as $notification) {
            try {
                // Dispatch job to queue
                SendScheduledNotification::dispatch($notification->id);
                
                Log::info("Scheduled notification job dispatched: {$notification->id}");
                
                // Update notification status to sending
                $notification->update(['status' => 'sending']);
                
            } catch (\Exception $e) {
                Log::error("Failed to schedule notification {$notification->id}: " . $e->getMessage());
                $notification->update(['status' => 'failed']);
            }
        }
    }

    /**
     * Schedule a specific notification.
     */
    public function scheduleNotification(Notification $notification): bool
    {
        try {
            if ($notification->scheduled_at && $notification->scheduled_at->isFuture()) {
                // Schedule for later
                $delay = $notification->scheduled_at->diffInSeconds(now());
                SendScheduledNotification::dispatch($notification->id)->delay($delay);
                
                Log::info("Notification {$notification->id} scheduled for {$notification->scheduled_at}");
                return true;
            } else {
                // Send immediately
                SendScheduledNotification::dispatch($notification->id);
                Log::info("Notification {$notification->id} scheduled for immediate sending");
                return true;
            }
        } catch (\Exception $e) {
            Log::error("Failed to schedule notification {$notification->id}: " . $e->getMessage());
            return false;
        }
    }

    /**
     * Check and process due notifications.
     */
    public function processDueNotifications(): void
    {
        $dueNotifications = Notification::where('status', 'scheduled')
            ->where('scheduled_at', '<=', now())
            ->get();

        foreach ($dueNotifications as $notification) {
            try {
                // Check if already being processed
                if ($notification->status === 'sending') {
                    continue;
                }

                // Dispatch job
                SendScheduledNotification::dispatch($notification->id);
                $notification->update(['status' => 'sending']);
                
                Log::info("Processing due notification: {$notification->id}");
                
            } catch (\Exception $e) {
                Log::error("Failed to process due notification {$notification->id}: " . $e->getMessage());
                $notification->update(['status' => 'failed']);
            }
        }
    }

    /**
     * Get queue statistics.
     */
    public function getQueueStats(): array
    {
        try {
            // This would require queue monitoring setup
            // For now, return basic stats
            $pendingCount = Notification::where('status', 'scheduled')
                ->where('scheduled_at', '<=', now())
                ->count();

            $sendingCount = Notification::where('status', 'sending')->count();
            $failedCount = Notification::where('status', 'failed')->count();

            return [
                'pending' => $pendingCount,
                'sending' => $sendingCount,
                'failed' => $failedCount,
                'queue_status' => $this->checkQueueStatus(),
            ];
        } catch (\Exception $e) {
            Log::error("Failed to get queue stats: " . $e->getMessage());
            return [
                'pending' => 0,
                'sending' => 0,
                'failed' => 0,
                'queue_status' => 'error',
            ];
        }
    }

    /**
     * Check if queue worker is running.
     */
    public function checkQueueStatus(): string
    {
        try {
            // Try to run a simple queue command to check status
            $output = [];
            $returnCode = null;
            
            exec('php artisan queue:work --once --quiet', $output, $returnCode);
            
            if ($returnCode === 0) {
                return 'active';
            } else {
                return 'inactive';
            }
        } catch (\Exception $e) {
            return 'unknown';
        }
    }

    /**
     * Retry failed notifications.
     */
    public function retryFailedNotifications(): int
    {
        $failedNotifications = Notification::where('status', 'failed')
            ->where('created_at', '>', now()->subHours(24)) // Only retry notifications from last 24 hours
            ->get();

        $retriedCount = 0;

        foreach ($failedNotifications as $notification) {
            try {
                // Reset status and reschedule
                $notification->update(['status' => 'scheduled']);
                $this->scheduleNotification($notification);
                $retriedCount++;
                
                Log::info("Retried failed notification: {$notification->id}");
                
            } catch (\Exception $e) {
                Log::error("Failed to retry notification {$notification->id}: " . $e->getMessage());
            }
        }

        return $retriedCount;
    }

    /**
     * Clean up old notifications.
     */
    public function cleanupOldNotifications(int $days = 30): int
    {
        try {
            $cutoffDate = now()->subDays($days);
            
            // Delete old delivered notifications
            $deletedCount = Notification::where('status', 'sent')
                ->where('sent_at', '<', $cutoffDate)
                ->delete();

            Log::info("Cleaned up {$deletedCount} old notifications");

            return $deletedCount;
        } catch (\Exception $e) {
            Log::error("Failed to cleanup old notifications: " . $e->getMessage());
            return 0;
        }
    }

    /**
     * Get notification processing report.
     */
    public function getProcessingReport(): array
    {
        $today = now()->startOfDay();
        $yesterday = now()->subDay()->startOfDay();

        $stats = [
            'today' => [
                'total' => Notification::whereDate('created_at', $today->toDateString())->count(),
                'sent' => Notification::whereDate('sent_at', $today->toDateString())->count(),
                'failed' => Notification::whereDate('created_at', $today->toDateString())
                    ->where('status', 'failed')->count(),
            ],
            'yesterday' => [
                'total' => Notification::whereDate('created_at', $yesterday->toDateString())->count(),
                'sent' => Notification::whereDate('sent_at', $yesterday->toDateString())->count(),
                'failed' => Notification::whereDate('created_at', $yesterday->toDateString())
                    ->where('status', 'failed')->count(),
            ],
            'queue' => $this->getQueueStats(),
        ];

        // Calculate success rate
        $totalSent = $stats['today']['sent'] + $stats['yesterday']['sent'];
        $totalFailed = $stats['today']['failed'] + $stats['yesterday']['failed'];
        $totalProcessed = $totalSent + $totalFailed;

        $stats['success_rate'] = $totalProcessed > 0 
            ? round(($totalSent / $totalProcessed) * 100, 2) 
            : 0;

        return $stats;
    }

    /**
     * Start queue worker (for development/testing).
     */
    public function startQueueWorker(): void
    {
        try {
            // This is for development only
            // In production, use supervisor or similar
            exec('php artisan queue:work --daemon &');
            Log::info('Queue worker started');
        } catch (\Exception $e) {
            Log::error('Failed to start queue worker: ' . $e->getMessage());
        }
    }
}
