<?php

namespace App\Services;

use App\Enums\EmailConfirmationType;
use App\Mail\ConfirmAccrualMail;
use App\Mail\ConfirmInvestmentMail;
use App\Mail\ConfirmWithdrawalMail;
use App\Models\EmailConfirmationToken;
use App\Models\InvestmentSetting;
use App\Models\User;
use App\Models\WithdrawalRequest;
use Carbon\CarbonInterface;
use Illuminate\Support\Facades\Mail;

class EmailActionConfirmation
{
    /**
     * Evita spam: no envía otro correo si ya existe un token vigente sin usar para la misma fecha de acreditación.
     */
    public function hasPendingAccrualPrompt(CarbonInterface $on): bool
    {
        $d = $on->copy()->startOfDay()->toDateString();

        return EmailConfirmationToken::query()
            ->where('type', EmailConfirmationType::AccrualRun->value)
            ->whereNull('used_at')
            ->where('expires_at', '>', now())
            ->where('payload->run_date', $d)
            ->exists();
    }

    public function notifyAccrualForDate(CarbonInterface $on): void
    {
        $date = $on->copy()->startOfDay();
        $d = $date->toDateString();

        if ($this->hasPendingAccrualPrompt($date)) {
            return;
        }

        ['plain' => $plain] = EmailConfirmationToken::mint(
            EmailConfirmationType::AccrualRun,
            null,
            null,
            ['run_date' => $d],
            $date->copy()->addHours(72),
        );

        $url = route('admin.confirm.accrual', ['token' => $plain], absolute: true);

        User::query()
            ->where('is_admin', true)
            ->orderBy('id')
            ->each(function (User $admin) use ($url, $d): void {
                Mail::to($admin->email)->send(new ConfirmAccrualMail($url, $d));
            });
    }

    public function sendInvestmentFromBalance(
        User $user,
        float $amount,
        int $durationMonths,
    ): void {
        $settings = InvestmentSetting::current();
        ['plain' => $plain] = EmailConfirmationToken::mint(
            EmailConfirmationType::InvestmentBalance,
            $user->id,
            null,
            [
                'amount' => round($amount, 2),
                'duration_months' => $durationMonths,
                'monthly_return_snapshot' => (float) $settings->monthly_return,
            ],
        );

        $url = route('confirm.email.investment', ['token' => $plain], absolute: true);
        $summary = sprintf(
            'Monto: %s US$ · Plazo: %d meses · Origen: saldo retirable.',
            number_format($amount, 2, '.', ''),
            $durationMonths,
        );

        Mail::to($user->email)->send(new ConfirmInvestmentMail($url, $summary));
    }

    public function sendInvestmentFromBlockchain(
        User $user,
        float $amount,
        int $durationMonths,
        string $txid,
    ): void {
        $settings = InvestmentSetting::current();
        ['plain' => $plain] = EmailConfirmationToken::mint(
            EmailConfirmationType::InvestmentBlockchain,
            $user->id,
            null,
            [
                'amount' => round($amount, 2),
                'duration_months' => $durationMonths,
                'txid' => $txid,
                'monthly_return_snapshot' => (float) $settings->monthly_return,
            ],
        );

        $url = route('confirm.email.investment', ['token' => $plain], absolute: true);
        $summary = sprintf(
            'Monto: %s US$ · Plazo: %d meses · TXID: %s · Origen: depósito externo.',
            number_format($amount, 2, '.', ''),
            $durationMonths,
            $txid,
        );

        Mail::to($user->email)->send(new ConfirmInvestmentMail($url, $summary));
    }

    public function sendWithdrawal(WithdrawalRequest $request): void
    {
        $request->loadMissing('requester');
        $user = $request->requester;
        if ($user === null) {
            return;
        }

        ['plain' => $plain] = EmailConfirmationToken::mint(
            EmailConfirmationType::WithdrawalRequest,
            $user->id,
            $request->id,
            [],
        );

        $url = route('confirm.email.withdrawal', ['token' => $plain], absolute: true);
        $summary = sprintf(
            'Monto bruto: %s US$ · Destino: %s (%s).',
            number_format((float) $request->amount, 2, '.', ''),
            $request->destination_currency_network ?? '—',
            $request->destination_label ?? $request->destination_address ?? '—',
        );

        Mail::to($user->email)->send(new ConfirmWithdrawalMail($url, $summary));
    }
}
