<?php

namespace Tests\Feature;

use App\Enums\SubscriptionStatus;
use App\Enums\TenantStatus;
use Illuminate\Foundation\Testing\RefreshDatabase;
use Tests\TestCase;

/**
 * Access is derived from dates on every read, not from whatever a cron last
 * wrote. These tests pin that, because "the scheduler did not run" must never
 * become "the shop kept trading for free".
 */
class SubscriptionAccessTest extends TestCase
{
    use RefreshDatabase;

    public function test_a_row_still_marked_active_but_past_its_end_date_reads_as_grace(): void
    {
        $product = $this->product();

        $subscription = $this->subscription($this->tenant($product), $this->plan($product), [
            'status' => SubscriptionStatus::Active,     // stale on purpose
            'ends_at' => now()->subDay(),
            'grace_ends_at' => now()->addDays(2),
        ]);

        $this->assertSame(SubscriptionStatus::Grace, $subscription->effectiveStatus());
        $this->assertSame('read_only', $subscription->accessState());
    }

    public function test_once_grace_is_over_the_shop_is_locked(): void
    {
        $product = $this->product();

        $subscription = $this->subscription($this->tenant($product), $this->plan($product), [
            'status' => SubscriptionStatus::Active,
            'ends_at' => now()->subDays(10),
            'grace_ends_at' => now()->subDays(7),
        ]);

        $this->assertSame(SubscriptionStatus::Expired, $subscription->effectiveStatus());
        $this->assertSame('locked', $subscription->accessState());
    }

    public function test_a_missing_grace_date_falls_back_to_the_configured_window(): void
    {
        config(['thinkrax.grace_days' => 3]);

        $product = $this->product();

        $subscription = $this->subscription($this->tenant($product), $this->plan($product), [
            'status' => SubscriptionStatus::Active,
            'ends_at' => now()->subDay(),
            'grace_ends_at' => null,
        ]);

        $this->assertSame(SubscriptionStatus::Grace, $subscription->effectiveStatus());
    }

    public function test_suspension_beats_a_perfectly_valid_subscription(): void
    {
        $product = $this->product();
        $tenant = $this->tenant($product, ['status' => TenantStatus::Suspended]);

        $subscription = $this->subscription($tenant, $this->plan($product), [
            'status' => SubscriptionStatus::Active,
            'ends_at' => now()->addMonths(6),
        ]);

        $this->assertSame('locked', $subscription->accessState());
    }

    public function test_entitlements_come_from_the_snapshot_not_the_live_plan(): void
    {
        $product = $this->product();
        $plan = $this->plan($product, ['features' => ['hr_module'], 'limits' => ['products' => 10000]]);

        $subscription = $this->subscription($this->tenant($product), $plan, [
            'features_snapshot' => ['hr_module', 'advanced_reports'],
            'limits_snapshot' => ['products' => 10000],
        ]);

        // The plan is later stripped back — a paying tenant must not notice.
        $plan->forceFill(['features' => [], 'limits' => ['products' => 10]])->save();

        $this->assertContains('advanced_reports', $subscription->refresh()->features());
        $this->assertSame(10000, (int) $subscription->limits()['products']);
    }

    public function test_days_remaining_never_goes_negative(): void
    {
        $product = $this->product();

        $subscription = $this->subscription($this->tenant($product), $this->plan($product), [
            'ends_at' => now()->subDays(30),
        ]);

        $this->assertSame(0, $subscription->daysRemaining());
    }
}
