<?php

namespace Tests\Unit\SystemCore\Models;

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

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

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

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

        $paymentTerm = CorePaymentTerm::create([
            'name' => 'Net 30',
            'code' => 'NET30',
            'days' => 30,
            'is_active' => true,
            'created_by_id' => $admin->id,
        ]);

        $this->assertDatabaseHas('core_payment_terms', [
            'name' => 'Net 30',
            'code' => 'NET30',
            'days' => 30,
        ]);
        $this->assertNotNull($paymentTerm->id);
    }

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

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

        $paymentTerm = $this->createCorePaymentTerm([
            'days' => 45,
            'created_by_id' => $admin->id,
        ]);

        $this->assertEquals(45, $paymentTerm->days);
        $this->assertIsInt($paymentTerm->days);
    }

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

        $paymentTerm = $this->createCorePaymentTerm([
            'is_active' => true,
            'created_by_id' => $admin->id,
        ]);

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

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

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

        $activePaymentTerm = $this->createCorePaymentTerm([
            'is_active' => true,
            'created_by_id' => $admin->id,
        ]);

        $inactivePaymentTerm = $this->createCorePaymentTerm([
            'is_active' => false,
            'created_by_id' => $admin->id,
        ]);

        $activeTerms = CorePaymentTerm::active()->get();

        $this->assertTrue($activeTerms->contains($activePaymentTerm));
        $this->assertFalse($activeTerms->contains($inactivePaymentTerm));
    }

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

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

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

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

        $paymentTerm->refresh();

        $this->assertCount(2, $paymentTerm->customers);
        $this->assertInstanceOf(CoreCustomer::class, $paymentTerm->customers->first());
    }

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

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

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

        $paymentTerm->refresh();

        $this->assertCount(2, $paymentTerm->suppliers);
        $this->assertInstanceOf(CoreSupplier::class, $paymentTerm->suppliers->first());
    }

    // ==========================================
    // Validation Tests
    // ==========================================

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

        $paymentTerm1 = $this->createCorePaymentTerm([
            'code' => 'UNIQUE-CODE',
            'created_by_id' => $admin->id,
        ]);

        // This should not create a duplicate code
        $count = CorePaymentTerm::where('code', 'UNIQUE-CODE')->count();
        $this->assertEquals(1, $count);
    }

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

        $paymentTerm = $this->createCorePaymentTerm([
            'name' => 'Required Name',
            'created_by_id' => $admin->id,
        ]);

        $this->assertNotEmpty($paymentTerm->name);
    }

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

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

        $paymentTerm = $this->createCorePaymentTerm(['created_by_id' => $admin->id]);
        $paymentTermId = $paymentTerm->id;

        $paymentTerm->delete();

        $this->assertSoftDeleted('core_payment_terms', ['id' => $paymentTermId]);
    }

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

        $paymentTerm = $this->createCorePaymentTerm(['created_by_id' => $admin->id]);
        $paymentTermId = $paymentTerm->id;

        $paymentTerm->delete();
        $this->assertSoftDeleted('core_payment_terms', ['id' => $paymentTermId]);

        $paymentTerm->restore();
        $this->assertDatabaseHas('core_payment_terms', [
            'id' => $paymentTermId,
            'deleted_at' => null,
        ]);
    }
}
