<?php

namespace Tests\Unit\SystemCore;

use Illuminate\Foundation\Testing\RefreshDatabase;
use Modules\SystemCore\App\Enums\CustomerType;
use Modules\SystemCore\App\Models\CoreCustomer;
use Tests\TestCase;
use Tests\Traits\CreatesSystemCoreEntities;
use Tests\Traits\CreatesUsers;

class CustomerBusinessLogicTest extends TestCase
{
    use CreatesSystemCoreEntities;
    use CreatesUsers;
    use RefreshDatabase;

    // ==========================================
    // Credit Limit Tests
    // ==========================================

    public function test_has_available_credit_returns_true_when_under_limit(): void
    {
        $admin = $this->createAdmin();
        $this->actingAs($admin);

        $customer = $this->createCoreCustomer([
            'credit_limit' => 10000.00,
            'credit_used' => 5000.00,
            'created_by_id' => $admin->id,
        ]);

        $this->assertTrue($customer->hasAvailableCredit(4000.00));
        $this->assertTrue($customer->hasAvailableCredit(5000.00)); // Exact available
    }

    public function test_has_available_credit_returns_false_when_over_limit(): void
    {
        $admin = $this->createAdmin();
        $this->actingAs($admin);

        $customer = $this->createCoreCustomer([
            'credit_limit' => 10000.00,
            'credit_used' => 5000.00,
            'created_by_id' => $admin->id,
        ]);

        $this->assertFalse($customer->hasAvailableCredit(5001.00));
        $this->assertFalse($customer->hasAvailableCredit(10000.00));
    }

    public function test_has_available_credit_with_zero_credit_limit(): void
    {
        $admin = $this->createAdmin();
        $this->actingAs($admin);

        $customer = $this->createCoreCustomer([
            'credit_limit' => 0,
            'credit_used' => 0,
            'created_by_id' => $admin->id,
        ]);

        $this->assertTrue($customer->hasAvailableCredit(0));
        $this->assertFalse($customer->hasAvailableCredit(1.00));
    }

    public function test_use_credit_succeeds_when_available(): void
    {
        $admin = $this->createAdmin();
        $this->actingAs($admin);

        $customer = $this->createCoreCustomer([
            'credit_limit' => 10000.00,
            'credit_used' => 3000.00,
            'created_by_id' => $admin->id,
        ]);

        $result = $customer->useCredit(2000.00);

        $this->assertTrue($result);
        $this->assertEquals(5000.00, $customer->fresh()->credit_used);
    }

    public function test_use_credit_fails_when_insufficient(): void
    {
        $admin = $this->createAdmin();
        $this->actingAs($admin);

        $customer = $this->createCoreCustomer([
            'credit_limit' => 5000.00,
            'credit_used' => 4000.00,
            'created_by_id' => $admin->id,
        ]);

        $result = $customer->useCredit(2000.00);

        $this->assertFalse($result);
        $this->assertEquals(4000.00, $customer->fresh()->credit_used);
    }

    public function test_release_credit_decreases_credit_used(): void
    {
        $admin = $this->createAdmin();
        $this->actingAs($admin);

        $customer = $this->createCoreCustomer([
            'credit_limit' => 10000.00,
            'credit_used' => 5000.00,
            'created_by_id' => $admin->id,
        ]);

        $customer->releaseCredit(2000.00);

        $this->assertEquals(3000.00, $customer->fresh()->credit_used);
    }

    public function test_release_credit_cannot_go_below_zero(): void
    {
        $admin = $this->createAdmin();
        $this->actingAs($admin);

        $customer = $this->createCoreCustomer([
            'credit_limit' => 10000.00,
            'credit_used' => 1000.00,
            'created_by_id' => $admin->id,
        ]);

        $customer->releaseCredit(5000.00); // More than used

        $this->assertEquals(0, $customer->fresh()->credit_used);
    }

    public function test_available_credit_attribute_calculation(): void
    {
        $admin = $this->createAdmin();
        $this->actingAs($admin);

        $customer = $this->createCoreCustomer([
            'credit_limit' => 10000.00,
            'credit_used' => 3500.00,
            'created_by_id' => $admin->id,
        ]);

        $this->assertEquals(6500.00, $customer->available_credit);
    }

    public function test_credit_calculation_handles_decimal_precision(): void
    {
        $admin = $this->createAdmin();
        $this->actingAs($admin);

        $customer = $this->createCoreCustomer([
            'credit_limit' => 1000.00,
            'credit_used' => 999.99,
            'created_by_id' => $admin->id,
        ]);

        $this->assertTrue($customer->hasAvailableCredit(0.01));
        $this->assertFalse($customer->hasAvailableCredit(0.02));
    }

    // ==========================================
    // Customer Segmentation Tests
    // ==========================================

    public function test_get_segment_returns_enterprise_for_high_lifetime_value(): void
    {
        $admin = $this->createAdmin();
        $this->actingAs($admin);

        $customer = $this->createCoreCustomer([
            'lifetime_value' => 150000.00,
            'created_by_id' => $admin->id,
        ]);

        $this->assertEquals('enterprise', $customer->getSegment());
    }

    public function test_get_segment_returns_premium_for_medium_lifetime_value(): void
    {
        $admin = $this->createAdmin();
        $this->actingAs($admin);

        $customer = $this->createCoreCustomer([
            'lifetime_value' => 75000.00,
            'created_by_id' => $admin->id,
        ]);

        $this->assertEquals('premium', $customer->getSegment());
    }

    public function test_get_segment_returns_standard_for_low_lifetime_value(): void
    {
        $admin = $this->createAdmin();
        $this->actingAs($admin);

        $customer = $this->createCoreCustomer([
            'lifetime_value' => 25000.00,
            'created_by_id' => $admin->id,
        ]);

        $this->assertEquals('standard', $customer->getSegment());
    }

    public function test_get_segment_returns_basic_for_no_purchases(): void
    {
        $admin = $this->createAdmin();
        $this->actingAs($admin);

        $customer = $this->createCoreCustomer([
            'lifetime_value' => 0,
            'created_by_id' => $admin->id,
        ]);

        $this->assertEquals('basic', $customer->getSegment());
    }

    public function test_get_segment_boundary_values(): void
    {
        $admin = $this->createAdmin();
        $this->actingAs($admin);

        // Test boundary at 100000 (enterprise threshold)
        $customer1 = $this->createCoreCustomer([
            'lifetime_value' => 100000.00,
            'created_by_id' => $admin->id,
        ]);
        $this->assertEquals('enterprise', $customer1->getSegment());

        // Test boundary at 50000 (premium threshold)
        $customer2 = $this->createCoreCustomer([
            'lifetime_value' => 50000.00,
            'created_by_id' => $admin->id,
        ]);
        $this->assertEquals('premium', $customer2->getSegment());

        // Test boundary at 10000 (standard threshold)
        $customer3 = $this->createCoreCustomer([
            'lifetime_value' => 10000.00,
            'created_by_id' => $admin->id,
        ]);
        $this->assertEquals('standard', $customer3->getSegment());

        // Just below standard
        $customer4 = $this->createCoreCustomer([
            'lifetime_value' => 9999.99,
            'created_by_id' => $admin->id,
        ]);
        $this->assertEquals('basic', $customer4->getSegment());
    }

    // ==========================================
    // Risk Level Tests
    // ==========================================

    public function test_get_risk_level_returns_high_for_blacklisted(): void
    {
        $admin = $this->createAdmin();
        $this->actingAs($admin);

        $customer = $this->createBlacklistedCustomer(['created_by_id' => $admin->id]);

        $this->assertEquals('high', $customer->getRiskLevel());
    }

    public function test_get_risk_level_returns_medium_for_high_credit_utilization(): void
    {
        $admin = $this->createAdmin();
        $this->actingAs($admin);

        $customer = $this->createCoreCustomer([
            'credit_limit' => 10000.00,
            'credit_used' => 8500.00, // 85% utilization
            'is_blacklisted' => false,
            'last_purchase_date' => now()->subDays(30),
            'created_by_id' => $admin->id,
        ]);

        $this->assertEquals('medium', $customer->getRiskLevel());
    }

    public function test_get_risk_level_returns_medium_for_inactive_customer(): void
    {
        $admin = $this->createAdmin();
        $this->actingAs($admin);

        $customer = $this->createCoreCustomer([
            'credit_limit' => 10000.00,
            'credit_used' => 1000.00, // Low credit utilization
            'is_blacklisted' => false,
            'last_purchase_date' => now()->subDays(100), // Inactive > 90 days
            'created_by_id' => $admin->id,
        ]);

        $this->assertEquals('medium', $customer->getRiskLevel());
    }

    public function test_get_risk_level_returns_low_for_healthy_customer(): void
    {
        $admin = $this->createAdmin();
        $this->actingAs($admin);

        $customer = $this->createCoreCustomer([
            'credit_limit' => 10000.00,
            'credit_used' => 2000.00, // 20% utilization
            'is_blacklisted' => false,
            'last_purchase_date' => now()->subDays(30), // Active
            'created_by_id' => $admin->id,
        ]);

        $this->assertEquals('low', $customer->getRiskLevel());
    }

    // ==========================================
    // Purchase Recording Tests
    // ==========================================

    public function test_record_purchase_increments_count_and_value(): void
    {
        $admin = $this->createAdmin();
        $this->actingAs($admin);

        $customer = $this->createCoreCustomer([
            'lifetime_value' => 0,
            'purchase_count' => 0,
            'created_by_id' => $admin->id,
        ]);

        $customer->recordPurchase(1000.00);

        $customer->refresh();
        $this->assertEquals(1, $customer->purchase_count);
        $this->assertEquals(1000.00, $customer->lifetime_value);
    }

    public function test_record_purchase_calculates_average_order_value(): void
    {
        $admin = $this->createAdmin();
        $this->actingAs($admin);

        $customer = $this->createCoreCustomer([
            'lifetime_value' => 0,
            'purchase_count' => 0,
            'average_order_value' => 0,
            'created_by_id' => $admin->id,
        ]);

        $customer->recordPurchase(1000.00);
        $customer->recordPurchase(500.00);
        $customer->recordPurchase(1500.00);

        $customer->refresh();
        $this->assertEquals(3, $customer->purchase_count);
        $this->assertEquals(3000.00, $customer->lifetime_value);
        $this->assertEquals(1000.00, $customer->average_order_value);
    }

    public function test_record_purchase_sets_first_purchase_date(): void
    {
        $admin = $this->createAdmin();
        $this->actingAs($admin);

        $customer = $this->createCoreCustomer([
            'first_purchase_date' => null,
            'created_by_id' => $admin->id,
        ]);

        $customer->recordPurchase(500.00);

        $customer->refresh();
        $this->assertNotNull($customer->first_purchase_date);
        $this->assertTrue($customer->first_purchase_date->isToday());
    }

    public function test_record_purchase_updates_last_purchase_date(): void
    {
        $admin = $this->createAdmin();
        $this->actingAs($admin);

        $customer = $this->createCoreCustomer([
            'last_purchase_date' => now()->subMonth(),
            'created_by_id' => $admin->id,
        ]);

        $customer->recordPurchase(500.00);

        $customer->refresh();
        $this->assertTrue($customer->last_purchase_date->isToday());
    }

    // ==========================================
    // B2B/B2C Tests
    // ==========================================

    public function test_is_b2b_returns_true_when_has_company(): void
    {
        $admin = $this->createAdmin();
        $this->actingAs($admin);

        // First create a company in CRMCore if module exists
        if (moduleExists('CRMCore')) {
            $company = \Modules\CRMCore\App\Models\Company::create([
                'name' => 'Test Company',
                'email' => 'company@test.com',
                'is_active' => true,
                'created_by_id' => $admin->id,
            ]);

            $customer = $this->createCoreCustomer([
                'company_id' => $company->id,
                'created_by_id' => $admin->id,
            ]);

            $this->assertTrue($customer->isB2B());
            $this->assertFalse($customer->isB2C());
        } else {
            $this->markTestSkipped('CRMCore module is not enabled');
        }
    }

    public function test_is_b2c_returns_true_when_no_company(): void
    {
        $admin = $this->createAdmin();
        $this->actingAs($admin);

        $customer = $this->createB2CCustomer(['created_by_id' => $admin->id]);

        $this->assertTrue($customer->isB2C());
        $this->assertFalse($customer->isB2B());
    }

    // ==========================================
    // Can Purchase Tests
    // ==========================================

    public function test_can_purchase_returns_true_for_active_non_blacklisted(): void
    {
        $admin = $this->createAdmin();
        $this->actingAs($admin);

        $customer = $this->createCoreCustomer([
            'is_active' => true,
            'is_blacklisted' => false,
            'created_by_id' => $admin->id,
        ]);

        $this->assertTrue($customer->canPurchase());
    }

    public function test_can_purchase_returns_false_for_inactive(): void
    {
        $admin = $this->createAdmin();
        $this->actingAs($admin);

        $customer = $this->createInactiveCustomer(['created_by_id' => $admin->id]);

        $this->assertFalse($customer->canPurchase());
    }

    public function test_can_purchase_returns_false_for_blacklisted(): void
    {
        $admin = $this->createAdmin();
        $this->actingAs($admin);

        $customer = $this->createBlacklistedCustomer(['created_by_id' => $admin->id]);

        $this->assertFalse($customer->canPurchase());
    }

    // ==========================================
    // Activity Status Tests
    // ==========================================

    public function test_is_new_returns_true_within_30_days(): void
    {
        $admin = $this->createAdmin();
        $this->actingAs($admin);

        $customer = $this->createCoreCustomer([
            'first_purchase_date' => now()->subDays(15),
            'created_by_id' => $admin->id,
        ]);

        $this->assertTrue($customer->isNew());
    }

    public function test_is_new_returns_false_after_30_days(): void
    {
        $admin = $this->createAdmin();
        $this->actingAs($admin);

        $customer = $this->createCoreCustomer([
            'first_purchase_date' => now()->subDays(45),
            'created_by_id' => $admin->id,
        ]);

        $this->assertFalse($customer->isNew());
    }

    public function test_is_inactive_returns_true_after_90_days(): void
    {
        $admin = $this->createAdmin();
        $this->actingAs($admin);

        $customer = $this->createCoreCustomer([
            'last_purchase_date' => now()->subDays(100),
            'created_by_id' => $admin->id,
        ]);

        $this->assertTrue($customer->isInactive());
    }

    public function test_is_inactive_returns_false_within_90_days(): void
    {
        $admin = $this->createAdmin();
        $this->actingAs($admin);

        $customer = $this->createCoreCustomer([
            'last_purchase_date' => now()->subDays(60),
            'created_by_id' => $admin->id,
        ]);

        $this->assertFalse($customer->isInactive());
    }

    // ==========================================
    // Scope Tests
    // ==========================================

    public function test_active_scope_filters_correctly(): void
    {
        $admin = $this->createAdmin();
        $this->actingAs($admin);

        $active1 = $this->createCoreCustomer(['created_by_id' => $admin->id]);
        $active2 = $this->createCoreCustomer(['created_by_id' => $admin->id]);
        $inactive = $this->createInactiveCustomer(['created_by_id' => $admin->id]);

        $activeCustomers = CoreCustomer::active()->get();

        $this->assertCount(2, $activeCustomers);
        $this->assertTrue($activeCustomers->contains($active1));
        $this->assertTrue($activeCustomers->contains($active2));
        $this->assertFalse($activeCustomers->contains($inactive));
    }

    public function test_not_blacklisted_scope_filters_correctly(): void
    {
        $admin = $this->createAdmin();
        $this->actingAs($admin);

        $normal = $this->createCoreCustomer(['created_by_id' => $admin->id]);
        $blacklisted = $this->createBlacklistedCustomer(['created_by_id' => $admin->id]);

        $nonBlacklistedCustomers = CoreCustomer::notBlacklisted()->get();

        $this->assertTrue($nonBlacklistedCustomers->contains($normal));
        $this->assertFalse($nonBlacklistedCustomers->contains($blacklisted));
    }

    public function test_vip_scope_filters_by_lifetime_value(): void
    {
        $admin = $this->createAdmin();
        $this->actingAs($admin);

        $vip = $this->createVipCustomer(['created_by_id' => $admin->id]);
        $regular = $this->createCoreCustomer([
            'lifetime_value' => 10000.00,
            'created_by_id' => $admin->id,
        ]);

        $vipCustomers = CoreCustomer::vip()->get();

        $this->assertTrue($vipCustomers->contains($vip));
        $this->assertFalse($vipCustomers->contains($regular));
    }

    public function test_by_type_scope_filters_correctly(): void
    {
        $admin = $this->createAdmin();
        $this->actingAs($admin);

        $b2b = $this->createB2BCustomer(['created_by_id' => $admin->id]);
        $b2c = $this->createB2CCustomer(['created_by_id' => $admin->id]);

        $b2bCustomers = CoreCustomer::byType(CustomerType::B2B)->get();
        $b2cCustomers = CoreCustomer::byType(CustomerType::B2C)->get();

        $this->assertTrue($b2bCustomers->contains($b2b));
        $this->assertFalse($b2bCustomers->contains($b2c));

        $this->assertTrue($b2cCustomers->contains($b2c));
        $this->assertFalse($b2cCustomers->contains($b2b));
    }
}
