<?php

declare(strict_types=1);

namespace Tests\Unit\Services\Platform;

use App\Models\Company;
use App\Models\Plan;
use App\Models\Subscription;
use App\Services\Platform\SaaSMetricsService;
use Illuminate\Foundation\Testing\DatabaseTransactions;
use Illuminate\Support\Facades\Cache;
use PHPUnit\Framework\Attributes\Test;
use Tests\TestCase;

class SaaSMetricsServiceTest extends TestCase
{
    use DatabaseTransactions;

    private SaaSMetricsService $service;

    protected function setUp(): void
    {
        parent::setUp();
        // Limpiar datos pre-existentes (seeder, etc.) dentro de la transacción.
        // DatabaseTransactions hace rollback automático al finalizar cada test,
        // restaurando el estado original de la DB.
        \DB::statement('SET FOREIGN_KEY_CHECKS=0');
        \DB::table('subscriptions')->delete();
        \DB::table('companies')->delete();
        \DB::statement('SET FOREIGN_KEY_CHECKS=1');
        Cache::flush();
        $this->service = app(SaaSMetricsService::class);
    }

    #[Test]
    public function it_calculates_company_stats()
    {
        // Create companies with different statuses
        Company::factory()->create(['status' => 'active']);
        Company::factory()->create(['status' => 'active']);
        Company::factory()->create(['status' => 'suspended']);
        Company::factory()->create(['status' => 'inactive']);

        $stats = $this->service->getCompanyStats();

        $this->assertEquals(4, $stats['total']);
        $this->assertEquals(2, $stats['active']);
        $this->assertEquals(1, $stats['suspended']);
        $this->assertEquals(1, $stats['inactive']);
    }

    #[Test]
    public function it_calculates_subscription_stats()
    {
        $company = Company::factory()->create();
        $plan = Plan::factory()->create(['price' => 100000]);

        // Create subscriptions with different statuses
        Subscription::factory()->create([
            'company_id' => $company->id,
            'plan_id' => $plan->id,
            'status' => Subscription::STATUS_ACTIVE,
        ]);
        Subscription::factory()->create([
            'company_id' => $company->id,
            'plan_id' => $plan->id,
            'status' => Subscription::STATUS_TRIAL,
        ]);
        Subscription::factory()->create([
            'company_id' => $company->id,
            'plan_id' => $plan->id,
            'status' => Subscription::STATUS_CANCELED,
        ]);

        $stats = $this->service->getSubscriptionStats();

        $this->assertEquals(3, $stats['total']);
        $this->assertEquals(2, $stats['active_total']); // active + trial
        $this->assertEquals(1, $stats['by_status'][Subscription::STATUS_ACTIVE]['count']);
        $this->assertEquals(1, $stats['by_status'][Subscription::STATUS_TRIAL]['count']);
        $this->assertEquals(1, $stats['by_status'][Subscription::STATUS_CANCELED]['count']);
    }

    #[Test]
    public function it_calculates_mrr_from_monthly_subscriptions()
    {
        $company = Company::factory()->create();
        $plan = Plan::factory()->create([
            'price' => 100000,
            'billing_cycle' => 'monthly',
        ]);

        // Two active monthly subscriptions at $100,000 each
        Subscription::factory()->count(2)->create([
            'company_id' => $company->id,
            'plan_id' => $plan->id,
            'status' => Subscription::STATUS_ACTIVE,
            'billing_cycle' => 'monthly',
            'amount_paid' => 100000,
            'starts_at' => now()->subMonth(),
        ]);

        $mrr = $this->service->calculateMRR();

        $this->assertEquals(200000, $mrr);
    }

    #[Test]
    public function it_calculates_mrr_from_annual_subscriptions()
    {
        $company = Company::factory()->create();
        $plan = Plan::factory()->create([
            'price' => 1200000, // $1,200,000 annual
            'billing_cycle' => 'annual',
        ]);

        // One annual subscription at $1,200,000
        Subscription::factory()->create([
            'company_id' => $company->id,
            'plan_id' => $plan->id,
            'status' => Subscription::STATUS_ACTIVE,
            'billing_cycle' => 'annual',
            'amount_paid' => 1200000,
            'starts_at' => now()->subMonth(),
        ]);

        $mrr = $this->service->calculateMRR();

        // Should be $100,000/month
        $this->assertEquals(100000, $mrr);
    }

    #[Test]
    public function it_excludes_canceled_subscriptions_from_mrr()
    {
        $company = Company::factory()->create();
        $plan = Plan::factory()->create(['price' => 100000]);

        // One active, one canceled
        Subscription::factory()->create([
            'company_id' => $company->id,
            'plan_id' => $plan->id,
            'status' => Subscription::STATUS_ACTIVE,
            'billing_cycle' => 'monthly',
            'amount_paid' => 100000,
            'starts_at' => now()->subMonth(),
        ]);

        Subscription::factory()->create([
            'company_id' => $company->id,
            'plan_id' => $plan->id,
            'status' => Subscription::STATUS_CANCELED,
            'billing_cycle' => 'monthly',
            'amount_paid' => 100000,
            'starts_at' => now()->subMonth(),
        ]);

        $mrr = $this->service->calculateMRR();

        // Only the active subscription should count
        $this->assertEquals(100000, $mrr);
    }

    #[Test]
    public function it_calculates_arr_from_mrr()
    {
        $company = Company::factory()->create();
        $plan = Plan::factory()->create(['price' => 100000]);

        Subscription::factory()->create([
            'company_id' => $company->id,
            'plan_id' => $plan->id,
            'status' => Subscription::STATUS_ACTIVE,
            'billing_cycle' => 'monthly',
            'amount_paid' => 100000,
            'starts_at' => now()->subMonth(),
        ]);

        $metrics = $this->service->getRevenueMetrics();

        $this->assertEquals(100000, $metrics['mrr']);
        $this->assertEquals(1200000, $metrics['arr']); // MRR * 12
    }

    #[Test]
    public function it_generates_mrr_trend_data()
    {
        $trend = $this->service->getMRRTrend(6);

        $this->assertCount(6, $trend);
        $this->assertArrayHasKey('month', $trend->first());
        $this->assertArrayHasKey('month_label', $trend->first());
        $this->assertArrayHasKey('mrr', $trend->first());
    }

    #[Test]
    public function it_returns_zero_churn_rate_with_no_subscriptions()
    {
        $churnRate = $this->service->calculateChurnRate();

        $this->assertEquals(0, $churnRate);
    }

    #[Test]
    public function it_returns_zero_trial_conversion_rate_with_no_trials()
    {
        $conversionRate = $this->service->calculateTrialConversionRate();

        $this->assertEquals(0, $conversionRate);
    }

    #[Test]
    public function it_returns_platform_summary()
    {
        $summary = $this->service->getPlatformSummary();

        $this->assertArrayHasKey('companies', $summary);
        $this->assertArrayHasKey('subscriptions', $summary);
        $this->assertArrayHasKey('revenue', $summary);
        $this->assertArrayHasKey('growth', $summary);
        $this->assertArrayHasKey('pending_requests', $summary);
    }

    #[Test]
    public function it_caches_platform_summary()
    {
        // First call
        $summary1 = $this->service->getPlatformSummary();

        // Create new company after first call
        Company::factory()->create(['status' => 'active']);

        // Second call should return cached data
        $summary2 = $this->service->getPlatformSummary();

        $this->assertEquals($summary1, $summary2);
    }

    #[Test]
    public function it_gets_subscriptions_by_plan()
    {
        $company = Company::factory()->create();
        $plan = Plan::factory()->create(['name' => 'Premium']);

        Subscription::factory()->create([
            'company_id' => $company->id,
            'plan_id' => $plan->id,
            'status' => Subscription::STATUS_ACTIVE,
        ]);

        $byPlan = $this->service->getSubscriptionsByPlan();

        $this->assertCount(1, $byPlan);
        $this->assertEquals('Premium', $byPlan->first()['plan_name']);
        $this->assertEquals(1, $byPlan->first()['count']);
    }
}
