<?php

declare(strict_types=1);

namespace Tests\Unit\Academy;

use App\Models\User;
use App\Services\Academy\AcademyAccessService;
use Illuminate\Foundation\Testing\RefreshDatabase;
use Laravel\Cashier\Subscription;
use Tests\TestCase;

final class AcademyAccessServiceTest extends TestCase
{
    use RefreshDatabase;

    protected function setUp(): void
    {
        parent::setUp();

        config()->set('academy_billing.subscription_name', 'academy');
        config()->set('academy_billing.plans', [
            'creator_monthly' => [
                'label' => 'Creator Monthly',
                'tier' => 'creator',
                'interval' => 'monthly',
                'stripe_price_id' => 'price_creator_month',
                'featured' => false,
            ],
            'pro_monthly' => [
                'label' => 'Pro Monthly',
                'tier' => 'pro',
                'interval' => 'monthly',
                'stripe_price_id' => 'price_pro_month',
                'featured' => true,
            ],
        ]);
    }

    public function test_current_tier_uses_cashier_subscription_items(): void
    {
        $user = User::factory()->create();
        $this->attachSubscription($user, 'sub_creator_unit', 'price_creator_month');

        $service = app(AcademyAccessService::class);

        $this->assertSame('creator', $service->currentTier($user));
        $this->assertTrue($service->canAccessContent($user, 'creator'));
        $this->assertFalse($service->canAccessContent($user, 'pro'));
    }

    public function test_pro_subscription_unlocks_creator_and_pro_content(): void
    {
        $user = User::factory()->create();
        $this->attachSubscription($user, 'sub_pro_unit', 'price_pro_month');

        $service = app(AcademyAccessService::class);

        $this->assertSame('pro', $service->currentTier($user));
        $this->assertTrue($service->canAccessContent($user, 'creator'));
        $this->assertTrue($service->canAccessContent($user, 'pro'));
    }

    public function test_grace_period_keeps_access_and_ended_subscription_loses_it(): void
    {
        $graceUser = User::factory()->create();
        $endedUser = User::factory()->create();

        $this->attachSubscription($graceUser, 'sub_grace_unit', 'price_creator_month', now()->addHour());
        $this->attachSubscription($endedUser, 'sub_ended_unit', 'price_creator_month', now()->subHour());

        $service = app(AcademyAccessService::class);

        $this->assertTrue($service->canAccessContent($graceUser, 'creator'));
        $this->assertFalse($service->canAccessContent($endedUser, 'creator'));
    }

    public function test_staff_and_moderators_bypass_billing_checks(): void
    {
        $admin = User::factory()->create(['role' => 'admin']);
        $moderator = User::factory()->create(['role' => 'moderator']);

        $service = app(AcademyAccessService::class);

        $this->assertSame('admin', $service->currentTier($admin));
        $this->assertSame('admin', $service->currentTier($moderator));
        $this->assertTrue($service->canAccessContent($admin, 'pro'));
        $this->assertTrue($service->canAccessContent($moderator, 'pro'));
    }

    private function attachSubscription(User $user, string $subscriptionId, string $priceId, ?\Illuminate\Support\Carbon $endsAt = null): Subscription
    {
        $subscription = $user->subscriptions()->create([
            'type' => 'academy',
            'stripe_id' => $subscriptionId,
            'stripe_status' => 'active',
            'stripe_price' => $priceId,
            'quantity' => 1,
            'ends_at' => $endsAt,
        ]);

        $subscription->items()->create([
            'stripe_id' => 'si_'.$subscriptionId,
            'stripe_product' => 'prod_'.($priceId === 'price_pro_month' ? 'pro' : 'creator'),
            'stripe_price' => $priceId,
            'quantity' => 1,
        ]);

        return $subscription;
    }
}