<?php

namespace Tests\Unit\SystemCore\Models;

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

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

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

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

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

        $address = CoreAddress::create([
            'entity_type' => 'customer',
            'entity_id' => $customer->id,
            'address_type' => 'billing',
            'address_line_1' => '123 Main Street',
            'city' => 'New York',
            'country' => 'US',
            'is_primary' => true,
        ]);

        $this->assertDatabaseHas('core_addresses', [
            'entity_type' => 'customer',
            'entity_id' => $customer->id,
            'address_line_1' => '123 Main Street',
        ]);
        $this->assertNotNull($address->id);
    }

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

        $supplier = $this->createCoreSupplier(['created_by_id' => $admin->id]);

        $address = CoreAddress::create([
            'entity_type' => 'supplier',
            'entity_id' => $supplier->id,
            'address_type' => 'billing',
            'address_line_1' => '456 Vendor Ave',
            'city' => 'Los Angeles',
            'country' => 'US',
            'is_primary' => true,
        ]);

        $this->assertDatabaseHas('core_addresses', [
            'entity_type' => 'supplier',
            'entity_id' => $supplier->id,
            'address_line_1' => '456 Vendor Ave',
        ]);
    }

    // ==========================================
    // Accessor Tests
    // ==========================================

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

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

        $address = $this->createCoreAddress([
            'entity_type' => 'customer',
            'entity_id' => $customer->id,
            'address_line_1' => '123 Main St',
            'address_line_2' => 'Apt 4B',
            'city' => 'New York',
            'state' => 'NY',
            'postal_code' => '10001',
            'country' => 'USA',
        ]);

        $this->assertEquals(
            '123 Main St, Apt 4B, New York, NY, 10001, USA',
            $address->full_address
        );
    }

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

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

        $address = $this->createCoreAddress([
            'entity_type' => 'customer',
            'entity_id' => $customer->id,
            'address_line_1' => '123 Main St',
            'address_line_2' => null,
            'city' => 'New York',
            'state' => null,
            'postal_code' => '',
            'country' => 'USA',
        ]);

        $this->assertEquals(
            '123 Main St, New York, USA',
            $address->full_address
        );
    }

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

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

        $address = $this->createCoreAddress([
            'entity_type' => 'customer',
            'entity_id' => $customer->id,
            'address_line_1' => 'Line 1',
            'address_line_2' => 'Line 2',
            'city' => 'City',
            'state' => 'State',
            'postal_code' => '12345',
            'country' => 'Country',
        ]);

        $fullAddress = $address->full_address;

        $this->assertStringContainsString('Line 1', $fullAddress);
        $this->assertStringContainsString('Line 2', $fullAddress);
        $this->assertStringContainsString('City', $fullAddress);
        $this->assertStringContainsString('State', $fullAddress);
        $this->assertStringContainsString('12345', $fullAddress);
        $this->assertStringContainsString('Country', $fullAddress);
    }

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

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

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

        $address = $this->createCoreAddress([
            'entity_type' => 'customer',
            'entity_id' => $customer->id,
            'latitude' => 40.7128,
            'longitude' => -74.0060,
        ]);

        $this->assertIsFloat($address->latitude);
        $this->assertIsFloat($address->longitude);
        $this->assertEqualsWithDelta(40.7128, $address->latitude, 0.0001);
        $this->assertEqualsWithDelta(-74.0060, $address->longitude, 0.0001);
    }

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

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

        $address = $this->createCoreAddress([
            'entity_type' => 'customer',
            'entity_id' => $customer->id,
            'is_primary' => true,
            'is_billing' => true,
            'is_shipping' => false,
        ]);

        $this->assertTrue($address->is_primary);
        $this->assertTrue($address->is_billing);
        $this->assertFalse($address->is_shipping);
        $this->assertIsBool($address->is_primary);
        $this->assertIsBool($address->is_billing);
        $this->assertIsBool($address->is_shipping);
    }

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

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

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

        $address = $this->createCoreAddress([
            'entity_type' => CoreCustomer::class,
            'entity_id' => $customer->id,
        ]);

        // Note: The entity() relationship uses morphTo
        // It expects entity_type to be the full class name or mapped alias
        $this->assertEquals($customer->id, $address->entity_id);
    }

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

        $supplier = $this->createCoreSupplier(['created_by_id' => $admin->id]);

        $address = $this->createCoreAddress([
            'entity_type' => CoreSupplier::class,
            'entity_id' => $supplier->id,
        ]);

        $this->assertEquals($supplier->id, $address->entity_id);
    }

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

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

        // Create address for customer
        $this->createCoreAddress([
            'entity_type' => 'customer',
            'entity_id' => $customer->id,
            'address_line_1' => 'Customer Address',
        ]);

        // Create address for supplier
        $this->createCoreAddress([
            'entity_type' => 'supplier',
            'entity_id' => $supplier->id,
            'address_line_1' => 'Supplier Address',
        ]);

        $customer->refresh();

        $this->assertCount(1, $customer->addresses);
        $this->assertEquals('Customer Address', $customer->addresses->first()->address_line_1);
    }

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

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

        $customer = $this->createCoreCustomer(['created_by_id' => $admin->id]);
        $address = $this->createCoreAddress([
            'entity_type' => 'customer',
            'entity_id' => $customer->id,
        ]);
        $addressId = $address->id;

        $address->delete();

        $this->assertSoftDeleted('core_addresses', ['id' => $addressId]);
    }

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

        $customer = $this->createCoreCustomer(['created_by_id' => $admin->id]);
        $address = $this->createCoreAddress([
            'entity_type' => 'customer',
            'entity_id' => $customer->id,
        ]);
        $addressId = $address->id;

        $address->delete();
        $this->assertSoftDeleted('core_addresses', ['id' => $addressId]);

        $address->restore();
        $this->assertDatabaseHas('core_addresses', [
            'id' => $addressId,
            'deleted_at' => null,
        ]);
    }
}
