<?php

namespace Tests\Unit\Models;

use Tests\TestCase;
use App\Models\Store;
use App\Models\User;
use App\Models\RawMaterial;
use App\Models\StoreRawMaterial;
use App\Models\ItemRequest;
use App\Models\StockOpname;
use Illuminate\Foundation\Testing\RefreshDatabase;

class StoreTest extends TestCase
{
    use RefreshDatabase;

    protected $testUser;

    protected function setUp(): void
    {
        parent::setUp();
        
        // Create test user
        $this->testUser = User::create([
            'name' => 'Test User',
            'email' => 'test@example.com',
            'password' => bcrypt('password'),
        ]);
    }

    /** @test */
    public function it_can_create_store_with_auto_generated_code()
    {
        $store = Store::create([
            'name' => 'Test Store',
            'address' => 'Test Address',
            'created_by' => $this->testUser->id,
            'delete_flag' => false
        ]);

        $this->assertNotNull($store->code);
        $this->assertStringStartsWith('BGM', $store->code);
        $this->assertEquals(7, strlen($store->code)); // BGM + 4 digits
    }

    /** @test */
    public function it_generates_sequential_codes()
    {
        $store1 = Store::create([
            'name' => 'Test Store 1',
            'address' => 'Test Address 1',
            'delete_flag' => false
        ]);

        $store2 = Store::create([
            'name' => 'Test Store 2',
            'address' => 'Test Address 2',
            'delete_flag' => false
        ]);

        $this->assertStringStartsWith('BGM', $store1->code);
        $this->assertStringStartsWith('BGM', $store2->code);
        
        $number1 = intval(substr($store1->code, 3));
        $number2 = intval(substr($store2->code, 3));
        
        $this->assertEquals($number1 + 1, $number2);
    }

    /** @test */
    public function it_has_correct_relationships()
    {
        $store = Store::create([
            'name' => 'Test Store',
            'address' => 'Test Address',
            'created_by' => $this->testUser->id,
            'updated_by' => $this->testUser->id,
            'delete_flag' => false
        ]);

        // Test user relationships
        $this->assertInstanceOf(User::class, $store->creator);
        $this->assertEquals($this->testUser->id, $store->creator->id);

        $this->assertInstanceOf(User::class, $store->modificator);
        $this->assertEquals($this->testUser->id, $store->modificator->id);
    }

    /** @test */
    public function it_can_have_raw_materials_relationship()
    {
        $store = Store::create([
            'name' => 'Test Store',
            'address' => 'Test Address',
            'delete_flag' => false
        ]);

        // Create raw material
        $rawMaterial = RawMaterial::create([
            'code' => 'RM001',
            'name' => 'Test Raw Material',
            'unit' => 'kg',
            'delete_flag' => false
        ]);

        // Create store raw material mapping
        StoreRawMaterial::create([
            'store_id' => $store->id,
            'raw_material_id' => $rawMaterial->id,
            'is_active' => true,
            'min_stock' => 10,
            'max_stock' => 100,
            'reorder_point' => 20,
            'delete_flag' => false
        ]);

        // Test relationships
        $this->assertCount(1, $store->rawMaterials);
        $this->assertEquals($rawMaterial->id, $store->rawMaterials->first()->id);
        
        $this->assertCount(1, $store->activeRawMaterials);
        $this->assertEquals($rawMaterial->id, $store->activeRawMaterials->first()->id);
        
        $this->assertCount(1, $store->storeRawMaterials);
    }

    /** @test */
    public function it_filters_active_raw_materials_correctly()
    {
        $store = Store::create([
            'name' => 'Test Store',
            'address' => 'Test Address',
            'delete_flag' => false
        ]);

        // Create raw materials
        $activeRM = RawMaterial::create([
            'code' => 'RM001',
            'name' => 'Active Raw Material',
            'unit' => 'kg',
            'delete_flag' => false
        ]);

        $inactiveRM = RawMaterial::create([
            'code' => 'RM002',
            'name' => 'Inactive Raw Material',
            'unit' => 'kg',
            'delete_flag' => false
        ]);

        // Create store raw material mappings
        StoreRawMaterial::create([
            'store_id' => $store->id,
            'raw_material_id' => $activeRM->id,
            'is_active' => true,
            'delete_flag' => false
        ]);

        StoreRawMaterial::create([
            'store_id' => $store->id,
            'raw_material_id' => $inactiveRM->id,
            'is_active' => false,
            'delete_flag' => false
        ]);

        // Test filtering
        $this->assertCount(2, $store->rawMaterials);
        $this->assertCount(1, $store->activeRawMaterials);
        $this->assertEquals($activeRM->id, $store->activeRawMaterials->first()->id);
    }

    /** @test */
    public function it_excludes_deleted_raw_materials()
    {
        $store = Store::create([
            'name' => 'Test Store',
            'address' => 'Test Address',
            'delete_flag' => false
        ]);

        $rawMaterial = RawMaterial::create([
            'code' => 'RM001',
            'name' => 'Test Raw Material',
            'unit' => 'kg',
            'delete_flag' => false
        ]);

        // Create deleted store raw material mapping
        StoreRawMaterial::create([
            'store_id' => $store->id,
            'raw_material_id' => $rawMaterial->id,
            'is_active' => true,
            'delete_flag' => true // Deleted
        ]);

        // Should not include deleted mappings
        $this->assertCount(0, $store->rawMaterials);
        $this->assertCount(0, $store->activeRawMaterials);
    }

    /** @test */
    public function it_can_have_item_requests()
    {
        $store = Store::create([
            'name' => 'Test Store',
            'address' => 'Test Address',
            'delete_flag' => false
        ]);

        ItemRequest::create([
            'spb_number' => 'SPB-TEST-001',
            'store_id' => $store->id,
            'request_type' => 'Regular',
            'status' => 'Draft',
            'delete_flag' => false
        ]);

        $this->assertCount(1, $store->itemRequests);
        $this->assertEquals('SPB-TEST-001', $store->itemRequests->first()->spb_number);
    }

    /** @test */
    public function it_can_have_stock_opnames()
    {
        $store = Store::create([
            'name' => 'Test Store',
            'address' => 'Test Address',
            'delete_flag' => false
        ]);

        StockOpname::create([
            'store_id' => $store->id,
            'so_number' => 'SO-TEST-001',
            'so_date' => now()->format('Y-m-d'),
            'status' => 'Draft',
            'delete_flag' => false
        ]);

        $this->assertCount(1, $store->stockOpnames);
        $this->assertEquals('SO-TEST-001', $store->stockOpnames->first()->so_number);
    }

    /** @test */
    public function it_handles_store_attributes_correctly()
    {
        $store = Store::create([
            'name' => 'Test Store',
            'store_type' => 'Retail',
            'document_type' => 'SPB',
            'address' => 'Test Address',
            'pic' => 'John Doe',
            'pic_phone' => '021-1234567',
            'pic_email' => 'john@teststore.com',
            'description' => 'Test store description',
            'bom_di' => '08:00',
            'bom_to' => '17:00',
            'status' => 'Active',
            'delete_flag' => false
        ]);

        $this->assertEquals('Test Store', $store->name);
        $this->assertEquals('Retail', $store->store_type);
        $this->assertEquals('SPB', $store->document_type);
        $this->assertEquals('Test Address', $store->address);
        $this->assertEquals('John Doe', $store->pic);
        $this->assertEquals('021-1234567', $store->pic_phone);
        $this->assertEquals('john@teststore.com', $store->pic_email);
        $this->assertEquals('Test store description', $store->description);
        $this->assertEquals('08:00', $store->bom_di);
        $this->assertEquals('17:00', $store->bom_to);
        $this->assertEquals('Active', $store->status);
    }

    /** @test */
    public function it_can_handle_inactive_date()
    {
        $inactiveDate = now()->format('Y-m-d');
        
        $store = Store::create([
            'name' => 'Inactive Store',
            'address' => 'Test Address',
            'status' => 'Inactive',
            'inactive_date' => $inactiveDate,
            'delete_flag' => false
        ]);

        $this->assertEquals($inactiveDate, $store->inactive_date);
        $this->assertEquals('Inactive', $store->status);
    }

    /** @test */
    public function it_handles_version_field()
    {
        $store = Store::create([
            'name' => 'Test Store',
            'address' => 'Test Address',
            'version' => 1,
            'delete_flag' => false
        ]);

        $this->assertEquals(1, $store->version);
        
        // Update version
        $store->update(['version' => 2]);
        $this->assertEquals(2, $store->fresh()->version);
    }

    /** @test */
    public function it_respects_delete_flag_in_code_generation()
    {
        // Create a store and then soft delete it
        $deletedStore = Store::create([
            'name' => 'Deleted Store',
            'address' => 'Test Address',
            'delete_flag' => false
        ]);
        
        $deletedStore->update(['delete_flag' => true]);
        
        // Create a new store - should not consider deleted store in code generation
        $newStore = Store::create([
            'name' => 'New Store',
            'address' => 'Test Address',
            'delete_flag' => false
        ]);

        // The new store should get the next available code, not considering deleted ones
        $this->assertStringStartsWith('BGM', $newStore->code);
    }

    /** @test */
    public function it_can_access_pivot_data_from_raw_materials()
    {
        $store = Store::create([
            'name' => 'Test Store',
            'address' => 'Test Address',
            'delete_flag' => false
        ]);

        $rawMaterial = RawMaterial::create([
            'code' => 'RM001',
            'name' => 'Test Raw Material',
            'unit' => 'kg',
            'delete_flag' => false
        ]);

        StoreRawMaterial::create([
            'store_id' => $store->id,
            'raw_material_id' => $rawMaterial->id,
            'is_active' => true,
            'min_stock' => 10,
            'max_stock' => 100,
            'reorder_point' => 20,
            'notes' => 'Test notes',
            'delete_flag' => false
        ]);

        $storeRM = $store->rawMaterials->first();
        
        $this->assertTrue($storeRM->pivot->is_active);
        $this->assertEquals(10, $storeRM->pivot->min_stock);
        $this->assertEquals(100, $storeRM->pivot->max_stock);
        $this->assertEquals(20, $storeRM->pivot->reorder_point);
        $this->assertEquals('Test notes', $storeRM->pivot->notes);
    }
}