<?php

namespace Tests\Unit\SystemCore\Models;

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

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

    // ==========================================
    // Creation Tests
    // ==========================================

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

        $customer = CoreCustomer::create([
            'name' => 'Test Customer',
            'email' => 'test@example.com',
            'customer_type' => CustomerType::B2B,
            'status' => CustomerStatus::Active,
            'is_active' => true,
            'created_by_id' => $admin->id,
        ]);

        $this->assertNotNull($customer->id);
        $this->assertEquals('Test Customer', $customer->name);
        $this->assertEquals('test@example.com', $customer->email);
        $this->assertEquals(CustomerType::B2B, $customer->customer_type);
        $this->assertEquals(CustomerStatus::Active, $customer->status);
        $this->assertTrue($customer->is_active);
    }

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

        // Create customer without customer_code to trigger auto-generation
        $customer = CoreCustomer::create([
            'name' => 'Test Customer',
            'customer_type' => CustomerType::B2B,
            'status' => CustomerStatus::Active,
            'is_active' => true,
            'created_by_id' => $admin->id,
        ]);

        $this->assertNotNull($customer->customer_code);
        $this->assertStringStartsWith('CUST-', $customer->customer_code);
    }

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

        $customer1 = CoreCustomer::create([
            'name' => 'Customer 1',
            'customer_type' => CustomerType::B2B,
            'status' => CustomerStatus::Active,
            'is_active' => true,
            'created_by_id' => $admin->id,
        ]);

        $customer2 = CoreCustomer::create([
            'name' => 'Customer 2',
            'customer_type' => CustomerType::B2B,
            'status' => CustomerStatus::Active,
            'is_active' => true,
            'created_by_id' => $admin->id,
        ]);

        $this->assertNotEquals($customer1->customer_code, $customer2->customer_code);
    }

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

        $customer = CoreCustomer::create([
            'customer_code' => 'CUSTOM-001',
            'name' => 'Custom Code Customer',
            'customer_type' => CustomerType::B2B,
            'status' => CustomerStatus::Active,
            'is_active' => true,
            'created_by_id' => $admin->id,
        ]);

        $this->assertEquals('CUSTOM-001', $customer->customer_code);
    }

    // ==========================================
    // Casting Tests
    // ==========================================

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

        $customer = $this->createCoreCustomer([
            'customer_type' => CustomerType::B2C,
            'created_by_id' => $admin->id,
        ]);

        $this->assertInstanceOf(CustomerType::class, $customer->customer_type);
    }

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

        $customer = $this->createCoreCustomer([
            'status' => CustomerStatus::Inactive,
            'created_by_id' => $admin->id,
        ]);

        $this->assertInstanceOf(CustomerStatus::class, $customer->status);
    }

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

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

        $this->assertIsNumeric($customer->credit_limit);
        $this->assertEquals(5000.56, $customer->credit_limit);
    }

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

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

        $this->assertIsBool($customer->is_active);
        $this->assertTrue($customer->is_active);
    }

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

        $tags = ['vip', 'wholesale', 'priority'];
        $customer = $this->createCoreCustomer([
            'tags' => $tags,
            'created_by_id' => $admin->id,
        ]);

        $this->assertIsArray($customer->tags);
        $this->assertEquals($tags, $customer->tags);
    }

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

        $metadata = ['source' => 'website', 'campaign' => 'summer_2025'];
        $customer = $this->createCoreCustomer([
            'metadata' => $metadata,
            'created_by_id' => $admin->id,
        ]);

        $this->assertIsArray($customer->metadata);
        $this->assertEquals('website', $customer->metadata['source']);
    }

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

        $customer = $this->createCoreCustomer([
            'latitude' => 40.7128,
            'longitude' => -74.0060,
            'created_by_id' => $admin->id,
        ]);

        $this->assertIsFloat($customer->latitude);
        $this->assertIsFloat($customer->longitude);
    }

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

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

        $activeCustomer = $this->createCoreCustomer([
            'is_active' => true,
            'status' => CustomerStatus::Active,
            'created_by_id' => $admin->id,
        ]);

        $inactiveCustomer = $this->createCoreCustomer([
            'is_active' => false,
            'status' => CustomerStatus::Inactive,
            'created_by_id' => $admin->id,
        ]);

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

        $this->assertTrue($customers->contains($activeCustomer));
        $this->assertFalse($customers->contains($inactiveCustomer));
    }

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

        $b2bCustomer = $this->createCoreCustomer([
            'customer_type' => CustomerType::B2B,
            'created_by_id' => $admin->id,
        ]);

        $b2cCustomer = $this->createCoreCustomer([
            'customer_type' => CustomerType::B2C,
            'created_by_id' => $admin->id,
        ]);

        $customers = CoreCustomer::byType(CustomerType::B2B)->get();

        $this->assertTrue($customers->contains($b2bCustomer));
        $this->assertFalse($customers->contains($b2cCustomer));
    }

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

        $b2bCustomer = $this->createCoreCustomer([
            'customer_type' => CustomerType::B2B,
            'created_by_id' => $admin->id,
        ]);

        $b2cCustomer = $this->createCoreCustomer([
            'customer_type' => CustomerType::B2C,
            'created_by_id' => $admin->id,
        ]);

        $customers = CoreCustomer::byType(CustomerType::B2C)->get();

        $this->assertFalse($customers->contains($b2bCustomer));
        $this->assertTrue($customers->contains($b2cCustomer));
    }

    // ==========================================
    // Relationship Tests
    // ==========================================

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

        $paymentTerm = $this->createCorePaymentTerm(['created_by_id' => $admin->id]);
        $customer = $this->createCoreCustomer([
            'payment_term_id' => $paymentTerm->id,
            'created_by_id' => $admin->id,
        ]);

        $this->assertNotNull($customer->paymentTerm);
        $this->assertEquals($paymentTerm->id, $customer->paymentTerm->id);
    }

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

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

        // Note: Sales orders would need to be created manually here
        // For now, just verify the relationship method returns the expected type
        $this->assertInstanceOf(\Illuminate\Database\Eloquent\Relations\HasMany::class, $customer->salesOrders());
    }

    // ==========================================
    // Static Method Tests
    // ==========================================

    public function test_generate_customer_code_returns_formatted_string(): void
    {
        $code = CoreCustomer::generateCustomerCode();

        $this->assertStringStartsWith('CUST-', $code);
        $this->assertEquals(11, strlen($code)); // CUST- + 6 digits
    }

    // ==========================================
    // Soft Delete Tests
    // ==========================================

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

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

        $customer->delete();

        $this->assertSoftDeleted('core_customers', ['id' => $customerId]);
    }

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

        $customer = $this->createCoreCustomer(['created_by_id' => $admin->id]);
        $customer->delete();
        $customer->restore();

        $this->assertDatabaseHas('core_customers', [
            'id' => $customer->id,
            'deleted_at' => null,
        ]);
    }

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

        $customer1 = $this->createCoreCustomer(['created_by_id' => $admin->id]);
        $customer2 = $this->createCoreCustomer(['created_by_id' => $admin->id]);
        $customer1->delete();

        $customers = CoreCustomer::all();

        $this->assertFalse($customers->contains($customer1));
        $this->assertTrue($customers->contains($customer2));
    }
}
