<?php

namespace App\Console\Commands;

use App\Jobs\SendBulkMailJob;
use App\Models\Mailing;
use Illuminate\Console\Command;
use Illuminate\Support\Facades\Log;

class RetryFailedMailings extends Command
{
    /**
     * The name and signature of the console command.
     *
     * @var string
     */
    protected $signature = 'mailings:retry-failed
                            {--mailing-id= : Specific mailing ID to retry}
                            {--hours= : Retry mailings failed within this many hours (default from config)}
                            {--dry-run : Show what would be retried without actually retrying}
                            {--force : Force retry even if within normal retry window}';

    /**
     * The console command description.
     *
     * @var string
     */
    protected $description = 'Retry failed email mailings that are outside their normal retry window';

    /**
     * Execute the console command.
     */
    public function handle()
    {
        $mailingId = $this->option('mailing-id');
        $hours = $this->option('hours') ?: timebank_config('bulk_mail.abandon_after_hours', 72);
        $dryRun = $this->option('dry-run');
        $force = $this->option('force');

        $this->info("Looking for failed mailings" . ($mailingId ? " (ID: {$mailingId})" : " from the last {$hours} hours") . "...");

        // Build query for mailings with failures
        $query = Mailing::where('status', 'sent')
            ->where('failed_count', '>', 0);

        if ($mailingId) {
            $query->where('id', $mailingId);
        } else {
            $query->where('sent_at', '>=', now()->subHours($hours));
        }

        $failedMailings = $query->get();

        if ($failedMailings->isEmpty()) {
            $this->info('No failed mailings found to retry.');
            return 0;
        }

        $this->info("Found {$failedMailings->count()} mailings with failures:");

        foreach ($failedMailings as $mailing) {
            $this->line("- Mailing #{$mailing->id}: {$mailing->title}");
            $this->line("  Failed: {$mailing->failed_count}, Sent: {$mailing->sent_count}, Total: {$mailing->recipients_count}");
            $this->line("  Sent at: {$mailing->sent_at}");
        }

        if ($dryRun) {
            $this->info("\n[DRY RUN] Would retry the above mailings. Use --force to actually retry.");
            return 0;
        }

        if (!$force && !$this->confirm('Do you want to retry these failed mailings?')) {
            $this->info('Operation cancelled.');
            return 0;
        }

        $totalRetried = 0;

        foreach ($failedMailings as $mailing) {
            $this->info("\nRetrying mailing #{$mailing->id}: {$mailing->title}");

            $retriedCount = $this->retryFailedMailing($mailing, $force);
            $totalRetried += $retriedCount;

            if ($retriedCount > 0) {
                $this->info("Queued {$retriedCount} retry jobs for mailing #{$mailing->id}");
            } else {
                $this->warn("No recipients to retry for mailing #{$mailing->id}");
            }
        }

        $this->info("\nCompleted! Total retry jobs queued: {$totalRetried}");

        return 0;
    }

    /**
     * Retry a specific failed mailing
     */
    protected function retryFailedMailing(Mailing $mailing, bool $force = false): int
    {
        // Check if mailing is still within automatic retry window
        $abandonAfterHours = timebank_config('bulk_mail.abandon_after_hours', 72);
        $retryWindowExpired = $mailing->sent_at->addHours($abandonAfterHours)->isPast();

        if (!$force && !$retryWindowExpired) {
            $this->warn("Mailing #{$mailing->id} is still within automatic retry window. Use --force to override.");
            return 0;
        }

        // Get all recipients and group by locale
        $recipientsByLocale = $this->getRecipientsGroupedByLocale($mailing);

        if (empty($recipientsByLocale)) {
            return 0;
        }

        $jobsQueued = 0;

        // Dispatch retry jobs for each locale
        foreach ($recipientsByLocale as $locale => $recipients) {
            if (!empty($recipients)) {
                $contentBlocks = $mailing->getContentBlocksForLocale($locale);

                SendBulkMailJob::dispatch($mailing, $locale, $contentBlocks, collect($recipients))
                    ->onQueue('emails');

                $jobsQueued++;
            }
        }

        // Reset failure count to allow fresh tracking
        if ($jobsQueued > 0) {
            $mailing->update([
                'failed_count' => 0,
                'status' => 'sending' // Reset to sending status
            ]);
        }

        return $jobsQueued;
    }

    /**
     * Get recipients grouped by locale for retry
     * Note: This is a simplified approach - in a production system you might want to track
     * individual recipient failures more precisely
     */
    protected function getRecipientsGroupedByLocale(Mailing $mailing): array
    {
        // Get all potential recipients again
        $allRecipients = $mailing->getRecipientsQuery()->get();

        if ($allRecipients->isEmpty()) {
            return [];
        }

        // Group by language preference
        $recipientsByLocale = [];

        foreach ($allRecipients as $recipient) {
            $locale = $recipient->lang_preference ?? timebank_config('base_language', 'en');

            // Only include locales that have content blocks
            $availableLocales = $mailing->getAvailablePostLocales();
            if (in_array($locale, $availableLocales)) {
                $recipientsByLocale[$locale][] = $recipient;
            } else {
                // Check if fallback is enabled
                if (timebank_config('bulk_mail.use_fallback_locale', true)) {
                    $fallbackLocale = timebank_config('bulk_mail.fallback_locale', 'en');
                    if (in_array($fallbackLocale, $availableLocales)) {
                        $recipientsByLocale[$fallbackLocale][] = $recipient;
                    }
                }
                // If fallback is disabled or fallback locale not available, skip this recipient
            }
        }

        return $recipientsByLocale;
    }
}
