<?php

namespace App\Console\Commands;

use App\Jobs\SendEmailJob;
use App\Models\ClientProduct;
use App\Models\ClientProductTrial;
use Illuminate\Console\Command;

/**
 * PRC-539 — Günlük 08:00'de trial bitiş tarihi tam olarak 3 gün sonraya denk gelen
 * free trial'ları saptayıp "trial_ending_soon" emaili gönderir.
 *
 * Idempotency: client_product_trials.ending_soon_sent_at. Kayıt NULL ise email
 * gönderilir ve kolon timestamp ile güncellenir; sonraki çalıştırmada skip edilir.
 * Böylece aynı trial için birden fazla e-posta gönderilmez.
 */
class SendTrialEndingSoonRemindersCommand extends Command
{
    protected $signature = 'trial:send-ending-soon-reminders
                            {--dry-run : Show what would be sent without actually sending}';

    protected $description = 'Send "trial ending soon" reminder emails to clients whose free trial ends in 3 days (PRC-539)';

    private const DAYS_BEFORE_END = 3;

    public function handle(): int
    {
        $dryRun = $this->option('dry-run');
        $targetDate = now()->addDays(self::DAYS_BEFORE_END)->toDateString();

        $this->info(sprintf(
            'Checking for trials ending on %s (in %d days)…%s',
            $targetDate,
            self::DAYS_BEFORE_END,
            $dryRun ? ' [DRY RUN]' : ''
        ));

        // Find active free trial rows whose ends_at falls on today+3.
        // whereNull('ending_soon_sent_at') is the idempotency guard:
        // once an email is dispatched the timestamp is recorded, preventing
        // re-sends on subsequent daily runs.
        $trials = ClientProductTrial::where('trial_mode', 'free')
            ->where('status', 'active')
            ->whereDate('ends_at', $targetDate)
            ->whereNull('ending_soon_sent_at')
            ->with([
                'clientProduct.client.currency',
                'clientProduct.product',
            ])
            ->get();

        if ($trials->isEmpty()) {
            $this->info('No trials ending in ' . self::DAYS_BEFORE_END . ' days — nothing to send.');

            return Command::SUCCESS;
        }

        $this->info("Found {$trials->count()} trial(s) to notify.");

        $sentCount = 0;
        $skippedCount = 0;

        foreach ($trials as $trial) {
            $cp = $trial->clientProduct;

            if (! $cp) {
                $this->warn("Trial #{$trial->id}: no ClientProduct — skipped.");
                $skippedCount++;
                continue;
            }

            $client = $cp->client;
            $product = $cp->product;

            if (! $client || ! $product) {
                $this->warn("Trial #{$trial->id} (cp #{$cp->id}): missing client or product — skipped.");
                $skippedCount++;
                continue;
            }

            if ($dryRun) {
                $this->line("Would send trial_ending_soon to {$client->email} (cp #{$cp->id}, trial #{$trial->id})");
                $sentCount++;
                continue;
            }

            try {
                $currencyCode = $client->currency?->code ?? 'USD';

                SendEmailJob::dispatch(
                    'Trial Ending Soon',
                    'client_product',
                    $cp->id,
                    [
                        'CLIENT_NAME'      => trim($client->first_name . ' ' . $client->last_name),
                        'PRODUCT_NAME'     => $product->name,
                        'TRIAL_ENDS_AT'    => $trial->ends_at
                            ? $trial->ends_at->format('Y-m-d')
                            : '—',
                        'TRIAL_DAYS'       => $product->trial_period_days ?? '—',
                        'RECURRING_AMOUNT' => number_format((float) $cp->recurring_amount, 2) . ' ' . $currencyCode,
                        'RECURRING_CYCLE'  => $cp->billingcycle ?? 'monthly',
                    ]
                );

                // Mark as sent to prevent re-sending (idempotency).
                $trial->update(['ending_soon_sent_at' => now()]);

                $this->info("Dispatched trial_ending_soon for cp #{$cp->id} ({$client->email})");
                $sentCount++;
            } catch (\Throwable $e) {
                $this->error("Failed for trial #{$trial->id} (cp #{$cp->id}): {$e->getMessage()}");
                $skippedCount++;
            }
        }

        $this->newLine();
        $this->info("Trial ending-soon reminders complete: sent={$sentCount}, skipped/failed={$skippedCount}");

        return Command::SUCCESS;
    }
}
