<?php

namespace Tests\Feature;

use App\Domain\Subscription\SubscriptionService;
use App\Models\Plan;
use App\Models\SubscriptionPayment;
use App\Models\Tenant;
use App\Support\Tenancy;
use Illuminate\Foundation\Testing\RefreshDatabase;
use Tests\TestCase;

class SubscriptionLifecycleTest extends TestCase
{
    use RefreshDatabase;

    protected function tenantWith(string $status, $endsAt, $graceEndsAt = null): Tenant
    {
        $tenant = Tenant::create(['name' => 'C', 'slug' => 'c'.rand(1000, 9999), 'status' => $status]);
        $tenant->subscription()->create([
            'plan_id' => Plan::first()->id,
            'status' => $status,
            'starts_at' => now()->subMonth(),
            'current_period_ends_at' => $endsAt,
            'grace_ends_at' => $graceEndsAt,
            'mrr_iqd' => $status === 'active' ? 50000 : 0,
        ]);

        return $tenant;
    }

    protected function setUp(): void
    {
        parent::setUp();
        $this->seed();
    }

    public function test_expired_active_moves_to_grace(): void
    {
        $tenant = $this->tenantWith('active', now()->subDay());

        app(SubscriptionService::class)->runLifecycle();

        $this->assertSame('grace', $tenant->subscription->fresh()->status);
        $this->assertSame('grace', $tenant->fresh()->status);
        $this->assertNotNull($tenant->subscription->fresh()->grace_ends_at);
    }

    public function test_expired_trial_moves_to_grace(): void
    {
        $tenant = $this->tenantWith('trialing', now()->subHour());
        app(SubscriptionService::class)->runLifecycle();
        $this->assertSame('grace', $tenant->subscription->fresh()->status);
    }

    public function test_grace_expired_moves_to_suspended_and_zeroes_mrr(): void
    {
        $tenant = $this->tenantWith('grace', now()->subDays(10), now()->subDay());
        $tenant->subscription->update(['mrr_iqd' => 50000]);

        app(SubscriptionService::class)->runLifecycle();

        $sub = $tenant->subscription->fresh();
        $this->assertSame('suspended', $sub->status);
        $this->assertSame('suspended', $tenant->fresh()->status);
        $this->assertSame(0, (int) $sub->mrr_iqd);
    }

    public function test_active_within_period_is_untouched(): void
    {
        $tenant = $this->tenantWith('active', now()->addDays(10));
        app(SubscriptionService::class)->runLifecycle();
        $this->assertSame('active', $tenant->subscription->fresh()->status);
    }

    public function test_payment_activation_stacks_from_future_period_end(): void
    {
        $tenant = $this->tenantWith('active', now()->addDays(5));
        $plan = Plan::first();
        app(Tenancy::class)->set($tenant);

        $payment = SubscriptionPayment::create([
            'tenant_id' => $tenant->id, 'plan_id' => $plan->id,
            'gateway' => 'zaincash', 'amount' => $plan->price_monthly_iqd,
            'currency' => 'IQD', 'status' => 'approved', 'period_months' => 1,
        ]);

        $sub = app(SubscriptionService::class)->activateFromPayment($payment);

        // New end ~ old end (+5d) + 1 month, not now + 1 month.
        $this->assertTrue($sub->current_period_ends_at->greaterThan(now()->addDays(30)));
        $this->assertSame('active', $sub->status);
        $this->assertSame((int) $plan->price_monthly_iqd, (int) $sub->mrr_iqd);
    }

    public function test_payment_reactivates_suspended_clinic(): void
    {
        $tenant = $this->tenantWith('suspended', now()->subDays(20), now()->subDays(10));
        $plan = Plan::first();
        app(Tenancy::class)->set($tenant);

        $payment = SubscriptionPayment::create([
            'tenant_id' => $tenant->id, 'plan_id' => $plan->id,
            'gateway' => 'superqi', 'amount' => $plan->price_monthly_iqd,
            'currency' => 'IQD', 'status' => 'approved', 'period_months' => 3,
        ]);

        app(SubscriptionService::class)->activateFromPayment($payment);

        $this->assertSame('active', $tenant->fresh()->status);
        $this->assertTrue($tenant->subscription->fresh()->current_period_ends_at->isFuture());
    }
}
