<?php

namespace Tests\Unit;

use App\Enums\CouponType;
use App\Jobs\SyncCouponToPaddle;
use App\Mail\GiftVoucherIssued;
use App\Models\Coupon;
use App\Models\GiftVoucher;
use App\Models\Package;
use App\Services\GiftVouchers\GiftVoucherService;
use Illuminate\Foundation\Testing\RefreshDatabase;
use Illuminate\Support\Facades\Bus;
use Illuminate\Support\Facades\Mail;
use Tests\TestCase;

class GiftVoucherServiceTest extends TestCase
{
    use RefreshDatabase;

    public function test_it_issues_voucher_and_coupon_from_paddle_payload(): void
    {
        $package = Package::factory()->create([
            'type' => 'endcustomer',
            'paddle_price_id' => 'pri_pkg_001',
            'price' => 59,
        ]);

        $payload = [
            'id' => 'txn_123',
            'event_type' => 'transaction.completed',
            'currency_code' => 'EUR',
            'totals' => [
                'grand_total' => [
                    'amount' => 5900,
                ],
            ],
            'custom_data' => [
                'type' => 'gift_card',
                'purchaser_email' => 'buyer@example.com',
                'recipient_email' => 'friend@example.com',
                'recipient_name' => 'Friend',
                'message' => 'Happy Day',
            ],
            'checkout_id' => 'chk_abc',
        ];

        Bus::fake([SyncCouponToPaddle::class]);

        $service = $this->app->make(GiftVoucherService::class);
        $voucher = $service->issueFromPaddle($payload);

        $this->assertInstanceOf(GiftVoucher::class, $voucher);
        $this->assertSame(59.00, (float) $voucher->amount);
        $this->assertNotNull($voucher->coupon);
        $this->assertSame($voucher->code, $voucher->coupon->code);
        $this->assertTrue($voucher->expires_at->greaterThan(now()->addYears(4)));
        $this->assertTrue($voucher->coupon->packages()->whereKey($package->id)->exists());
        Bus::assertDispatched(SyncCouponToPaddle::class);
    }

    public function test_redeeming_coupon_marks_voucher_redeemed(): void
    {
        $voucher = GiftVoucher::factory()->create([
            'status' => GiftVoucher::STATUS_ISSUED,
            'amount' => 29,
        ]);

        $coupon = Coupon::factory()->create([
            'code' => $voucher->code,
            'type' => CouponType::FLAT,
            'amount' => 29,
            'currency' => 'EUR',
            'paddle_discount_id' => null,
        ]);

        $voucher->coupon()->associate($coupon)->save();

        $service = $this->app->make(GiftVoucherService::class);
        $service->markRedeemed($coupon, 'txn_999');

        $this->assertSame(GiftVoucher::STATUS_REDEEMED, $voucher->refresh()->status);
        $this->assertNotNull($voucher->redeemed_at);
    }

    public function test_it_sends_notifications_to_purchaser_and_recipient_once(): void
    {
        Mail::fake();
        Bus::fake([SyncCouponToPaddle::class]);
        config()->set('gift-vouchers.reminder_days', 0);
        config()->set('gift-vouchers.expiry_reminder_days', 0);

        Package::factory()->create([
            'type' => 'endcustomer',
            'paddle_price_id' => 'pri_pkg_001',
            'price' => 29,
        ]);

        $payload = [
            'id' => 'txn_456',
            'currency_code' => 'EUR',
            'totals' => [
                'grand_total' => [
                    'amount' => 2900,
                ],
            ],
            'custom_data' => [
                'type' => 'gift_voucher',
                'purchaser_email' => 'buyer@example.com',
                'recipient_email' => 'friend@example.com',
                'app_locale' => 'de',
            ],
            'checkout_id' => 'chk_notif',
        ];

        $service = $this->app->make(GiftVoucherService::class);
        $voucher = $service->issueFromPaddle($payload);

        Mail::assertQueued(GiftVoucherIssued::class, 2);
        $this->assertTrue((bool) ($voucher->metadata['notifications_sent'] ?? false));

        // Second call (duplicate webhook) should not resend
        $service->issueFromPaddle($payload);
        Mail::assertQueued(GiftVoucherIssued::class, 2);
    }

    public function test_it_resolves_amount_from_tier_by_price_id(): void
    {
        config()->set('gift-vouchers.tiers', [
            [
                'key' => 'gift-standard-usd',
                'label' => 'Gift Standard (USD)',
                'amount' => 65.00,
                'currency' => 'USD',
                'paddle_price_id' => 'pri_usd_123',
            ],
        ]);

        Bus::fake([SyncCouponToPaddle::class]);
        Mail::fake();

        $payload = [
            'id' => 'txn_usd',
            'price_id' => 'pri_usd_123',
            'currency_code' => 'USD',
        ];

        $service = $this->app->make(GiftVoucherService::class);
        $voucher = $service->issueFromPaddle($payload);

        $this->assertSame(65.00, (float) $voucher->amount);
        $this->assertSame('USD', $voucher->currency);
    }
}
