<?php

declare(strict_types=1);

namespace Tests\Feature;

use App\Models\Company;
use App\Models\Subscription;
use App\Models\User;
use App\Notifications\SubscriptionExpiringNotification;
use Carbon\Carbon;
use Illuminate\Foundation\Testing\DatabaseTransactions;
use Illuminate\Support\Facades\Notification;
use PHPUnit\Framework\Attributes\Test;
use Spatie\Permission\Models\Role;
use Tests\TestCase;

/**
 * #166 — avisos in-app de vencimiento (prueba/suscripción) a T-3 y T-1 días.
 * El comando `subscriptions:notify-expiring` notifica a los admins de la empresa.
 */
class SubscriptionExpiryNoticeTest extends TestCase
{
    use DatabaseTransactions;

    private function companyWithAdmin(): array
    {
        Role::firstOrCreate(['name' => 'admin', 'guard_name' => 'web']);
        $company = Company::factory()->create();
        $admin = User::factory()->create(['company_id' => $company->id]);
        $admin->assignRole('admin');

        return [$company, $admin];
    }

    private function subscription(Company $company, string $status, string $field, Carbon $when): Subscription
    {
        return Subscription::factory()->create([
            'company_id' => $company->id,
            'plan_id' => null,
            'status' => $status,
            $field => $when,
        ]);
    }

    #[Test]
    public function a_trial_ending_in_three_days_notifies_the_company_admin(): void
    {
        Notification::fake();
        [$company, $admin] = $this->companyWithAdmin();
        $this->subscription($company, Subscription::STATUS_TRIAL, 'ends_at', now()->addDays(3));

        $this->artisan('subscriptions:notify-expiring')->assertSuccessful();

        Notification::assertSentTo(
            $admin,
            SubscriptionExpiringNotification::class,
            fn (SubscriptionExpiringNotification $n) => $n->context === SubscriptionExpiringNotification::CONTEXT_TRIAL && $n->daysLeft === 3,
        );
    }

    #[Test]
    public function an_active_subscription_ending_in_one_day_notifies_with_renewal_context(): void
    {
        Notification::fake();
        [$company, $admin] = $this->companyWithAdmin();
        $this->subscription($company, Subscription::STATUS_ACTIVE, 'ends_at', now()->addDay());

        $this->artisan('subscriptions:notify-expiring')->assertSuccessful();

        Notification::assertSentTo(
            $admin,
            SubscriptionExpiringNotification::class,
            fn (SubscriptionExpiringNotification $n) => $n->context === SubscriptionExpiringNotification::CONTEXT_RENEWAL && $n->daysLeft === 1,
        );
    }

    #[Test]
    public function a_subscription_ending_outside_the_thresholds_is_not_notified(): void
    {
        Notification::fake();
        [$company, $admin] = $this->companyWithAdmin();
        $this->subscription($company, Subscription::STATUS_TRIAL, 'ends_at', now()->addDays(5));

        $this->artisan('subscriptions:notify-expiring')->assertSuccessful();

        Notification::assertNothingSentTo($admin);
    }
}
