<?php

namespace Tests\Feature;

use Tests\TestCase;
use App\Models\ItemRequest;
use App\Models\Store;
use App\Models\StockOpname;
use App\Models\User;
use App\Models\NumberingFormat;
use Carbon\Carbon;
use Illuminate\Foundation\Testing\RefreshDatabase;

class ItemRequestsControllerTest extends TestCase
{
    use RefreshDatabase;

    protected $user;
    protected $store;
    protected $stockOpname;

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

        $this->store = Store::create([
            'code' => 'TST001',
            'name' => 'Test Store',
            'address' => 'Test Address',
            'delete_flag' => false
        ]);

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

        // Create numbering format
        NumberingFormat::create([
            'store_id' => $this->store->id,
            'document_type' => 'SPB',
            'format_pattern' => '{DOCTYPE}{SEP}{STORE}{SEP}{YY}{MM}{SEP}{NUMBER}',
            'separator' => '-',
            'number_length' => 4,
            'reset_period' => 'Monthly',
            'current_number' => 0,
            'is_active' => true,
            'delete_flag' => false
        ]);
    }

    /** @test */
    public function it_can_display_item_requests_index_page()
    {
        $this->actingAs($this->user);

        $response = $this->get(route('item_requests.index'));

        $response->assertStatus(200);
        $response->assertViewIs('t-item-requests.index');
        $response->assertViewHas('variables');
    }

    /** @test */
    public function it_can_get_item_requests_data_via_ajax()
    {
        $this->actingAs($this->user);

        ItemRequest::create([
            'spb_number' => 'SPB-TEST-001',
            'store_id' => $this->store->id,
            'stock_opname_id' => $this->stockOpname->id,
            'request_type' => 'Regular',
            'request_date' => Carbon::now()->format('Y-m-d'),
            'delivery_date' => Carbon::now()->addDays(3)->format('Y-m-d'),
            'status' => ItemRequest::STATUS_DRAFT,
            'delete_flag' => false
        ]);

        $response = $this->json('GET', route('item_requests.index'), [
            'draw' => 1,
            'start' => 0,
            'length' => 10,
            'search' => ['value' => ''],
            'order' => [['column' => 1, 'dir' => 'desc']]
        ], [
            'X-Requested-With' => 'XMLHttpRequest'
        ]);

        $response->assertStatus(200);
        $response->assertJsonStructure([
            'draw',
            'recordsTotal',
            'recordsFiltered',
            'data'
        ]);

        $data = $response->json('data');
        $this->assertCount(1, $data);
        $this->assertStringContainsString('SPB-TEST-001', $data[0][1]);
    }

    /** @test */
    public function it_can_filter_by_store()
    {
        $this->actingAs($this->user);

        $anotherStore = Store::create([
            'code' => 'TST002',
            'name' => 'Another Store',
            'address' => 'Another Address',
            'delete_flag' => false
        ]);

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

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

        $response = $this->json('GET', route('item_requests.index'), [
            'draw' => 1,
            'start' => 0,
            'length' => 10,
            'store_id' => $this->store->id,
            'search' => ['value' => ''],
            'order' => [['column' => 1, 'dir' => 'desc']]
        ], [
            'X-Requested-With' => 'XMLHttpRequest'
        ]);

        $response->assertStatus(200);
        $data = $response->json('data');
        $this->assertCount(1, $data);
        $this->assertStringContainsString('SPB-TEST-001', $data[0][1]);
    }

    /** @test */
    public function it_can_filter_by_status()
    {
        $this->actingAs($this->user);

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

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

        $response = $this->json('GET', route('item_requests.index'), [
            'draw' => 1,
            'start' => 0,
            'length' => 10,
            'status' => ItemRequest::STATUS_DRAFT,
            'search' => ['value' => ''],
            'order' => [['column' => 1, 'dir' => 'desc']]
        ], [
            'X-Requested-With' => 'XMLHttpRequest'
        ]);

        $response->assertStatus(200);
        $data = $response->json('data');
        $this->assertCount(1, $data);
        $this->assertStringContainsString('SPB-DRAFT-001', $data[0][1]);
    }

    /** @test */
    public function it_can_search_item_requests()
    {
        $this->actingAs($this->user);

        ItemRequest::create([
            'spb_number' => 'SPB-SEARCH-001',
            'store_id' => $this->store->id,
            'request_type' => 'Regular',
            'status' => ItemRequest::STATUS_DRAFT,
            'notes' => 'Special search notes',
            'delete_flag' => false
        ]);

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

        $response = $this->json('GET', route('item_requests.index'), [
            'draw' => 1,
            'start' => 0,
            'length' => 10,
            'search' => ['value' => 'SEARCH'],
            'order' => [['column' => 1, 'dir' => 'desc']]
        ], [
            'X-Requested-With' => 'XMLHttpRequest'
        ]);

        $response->assertStatus(200);
        $data = $response->json('data');
        $this->assertCount(1, $data);
        $this->assertStringContainsString('SPB-SEARCH-001', $data[0][1]);
    }

    /** @test */
    public function it_can_display_create_item_request_form()
    {
        $this->actingAs($this->user);

        $response = $this->get(route('item_requests.create'));

        $response->assertStatus(200);
        $response->assertViewIs('t-item-requests.form');
        $response->assertViewHas('data');
        $response->assertViewHas('variables');
    }

    /** @test */
    public function it_can_create_new_item_request()
    {
        $this->actingAs($this->user);

        $requestData = [
            'store_id' => $this->store->id,
            'stock_opname_id' => $this->stockOpname->id,
            'request_type' => 'Regular',
            'request_date' => Carbon::now()->format('Y-m-d'),
            'delivery_date' => Carbon::now()->addDays(3)->format('Y-m-d'),
            'notes' => 'Test item request'
        ];

        $response = $this->json('POST', route('item_requests.store'), $requestData);

        $response->assertStatus(200);
        $response->assertJson(['success']);

        $this->assertDatabaseHas('t_item_requests', [
            'store_id' => $this->store->id,
            'stock_opname_id' => $this->stockOpname->id,
            'request_type' => 'Regular',
            'status' => ItemRequest::STATUS_DRAFT,
            'notes' => 'Test item request',
            'delete_flag' => false
        ]);

        // Check SPB number was generated
        $itemRequest = ItemRequest::where('store_id', $this->store->id)->first();
        $this->assertNotNull($itemRequest->spb_number);
        $this->assertStringContainsString('SPB', $itemRequest->spb_number);
    }

    /** @test */
    public function it_validates_required_fields_when_creating()
    {
        $this->actingAs($this->user);

        $response = $this->json('POST', route('item_requests.store'), []);

        $response->assertStatus(422);
        $response->assertJsonValidationErrors([
            'store_id',
            'request_type',
            'request_date'
        ]);
    }

    /** @test */
    public function it_validates_store_exists()
    {
        $this->actingAs($this->user);

        $response = $this->json('POST', route('item_requests.store'), [
            'store_id' => 99999,
            'request_type' => 'Regular',
            'request_date' => Carbon::now()->format('Y-m-d')
        ]);

        $response->assertStatus(422);
        $response->assertJsonValidationErrors(['store_id']);
    }

    /** @test */
    public function it_validates_request_type_enum()
    {
        $this->actingAs($this->user);

        $response = $this->json('POST', route('item_requests.store'), [
            'store_id' => $this->store->id,
            'request_type' => 'InvalidType',
            'request_date' => Carbon::now()->format('Y-m-d')
        ]);

        $response->assertStatus(422);
        $response->assertJsonValidationErrors(['request_type']);
    }

    /** @test */
    public function it_validates_date_formats()
    {
        $this->actingAs($this->user);

        $response = $this->json('POST', route('item_requests.store'), [
            'store_id' => $this->store->id,
            'request_type' => 'Regular',
            'request_date' => 'invalid-date',
            'delivery_date' => 'invalid-date'
        ]);

        $response->assertStatus(422);
        $response->assertJsonValidationErrors(['request_date', 'delivery_date']);
    }

    /** @test */
    public function it_can_display_edit_item_request_form()
    {
        $this->actingAs($this->user);

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

        $response = $this->get(route('item_requests.edit', $itemRequest));

        $response->assertStatus(200);
        $response->assertViewIs('t-item-requests.form');
        $response->assertViewHas('data', $itemRequest);
    }

    /** @test */
    public function it_prevents_editing_non_draft_requests()
    {
        $this->actingAs($this->user);

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

        $response = $this->get(route('item_requests.edit', $itemRequest));

        $response->assertRedirect(route('item_requests.index'));
        $response->assertSessionHas('error');
    }

    /** @test */
    public function it_can_update_existing_item_request()
    {
        $this->actingAs($this->user);

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

        $updateData = [
            'store_id' => $this->store->id,
            'request_type' => 'Temporary',
            'request_date' => Carbon::now()->format('Y-m-d'),
            'delivery_date' => Carbon::now()->addDays(5)->format('Y-m-d'),
            'notes' => 'Updated notes'
        ];

        $response = $this->json('POST', route('item_requests.store', $itemRequest->id), $updateData);

        $response->assertStatus(200);
        $response->assertJson(['success']);

        $itemRequest->refresh();
        $this->assertEquals('Temporary', $itemRequest->request_type);
        $this->assertEquals('Updated notes', $itemRequest->notes);
    }

    /** @test */
    public function it_prevents_updating_non_draft_requests()
    {
        $this->actingAs($this->user);

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

        $response = $this->json('POST', route('item_requests.store', $itemRequest->id), [
            'store_id' => $this->store->id,
            'request_type' => 'Regular',
            'request_date' => Carbon::now()->format('Y-m-d')
        ]);

        $response->assertStatus(200);
        $response->assertJson(['warning']);
    }

    /** @test */
    public function it_can_display_item_request_details()
    {
        $this->actingAs($this->user);

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

        $response = $this->get(route('item_requests.show', $itemRequest));

        $response->assertStatus(200);
        $response->assertViewIs('t-item-requests.show');
        $response->assertViewHas('data', $itemRequest);
    }

    /** @test */
    public function it_can_delete_item_request()
    {
        $this->actingAs($this->user);

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

        $response = $this->delete(route('item_requests.destroy', $itemRequest));

        $response->assertRedirect(route('item_requests.index'));
        $response->assertSessionHas('success');

        $itemRequest->refresh();
        $this->assertTrue($itemRequest->delete_flag);
    }

    /** @test */
    public function it_prevents_deleting_non_draft_requests()
    {
        $this->actingAs($this->user);

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

        $response = $this->json('DELETE', route('item_requests.destroy', $itemRequest));

        $response->assertStatus(200);
        $response->assertJson(['warning']);

        $itemRequest->refresh();
        $this->assertFalse($itemRequest->delete_flag);
    }

    /** @test */
    public function it_can_submit_item_request()
    {
        $this->actingAs($this->user);

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

        $response = $this->json('POST', route('item_requests.submit', $itemRequest));

        $response->assertStatus(200);
        $response->assertJson(['success']);

        $itemRequest->refresh();
        $this->assertEquals(ItemRequest::STATUS_SUBMITTED, $itemRequest->status);
    }

    /** @test */
    public function it_prevents_submitting_non_draft_requests()
    {
        $this->actingAs($this->user);

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

        $response = $this->json('POST', route('item_requests.submit', $itemRequest));

        $response->assertStatus(200);
        $response->assertJson(['warning']);
    }

    /** @test */
    public function it_can_approve_item_request()
    {
        $this->actingAs($this->user);

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

        $response = $this->json('POST', route('item_requests.approve', $itemRequest));

        $response->assertStatus(200);
        $response->assertJson(['success']);

        $itemRequest->refresh();
        $this->assertEquals(ItemRequest::STATUS_APPROVED, $itemRequest->status);
    }

    /** @test */
    public function it_prevents_approving_non_submitted_requests()
    {
        $this->actingAs($this->user);

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

        $response = $this->json('POST', route('item_requests.approve', $itemRequest));

        $response->assertStatus(200);
        $response->assertJson(['warning']);
    }

    /** @test */
    public function it_enforces_business_rule_for_regular_spb()
    {
        $this->actingAs($this->user);

        // Create existing regular SPB for the stock opname
        ItemRequest::create([
            'spb_number' => 'SPB-EXISTING-001',
            'store_id' => $this->store->id,
            'stock_opname_id' => $this->stockOpname->id,
            'request_type' => 'Regular',
            'status' => ItemRequest::STATUS_SUBMITTED,
            'delete_flag' => false
        ]);

        // Try to create another regular SPB for the same stock opname
        $response = $this->json('POST', route('item_requests.store'), [
            'store_id' => $this->store->id,
            'stock_opname_id' => $this->stockOpname->id,
            'request_type' => 'Regular',
            'request_date' => Carbon::now()->format('Y-m-d')
        ]);

        $response->assertStatus(200);
        $response->assertJson(['warning']);
    }

    /** @test */
    public function it_allows_temporary_spb_even_if_regular_exists()
    {
        $this->actingAs($this->user);

        // Create existing regular SPB
        ItemRequest::create([
            'spb_number' => 'SPB-REGULAR-001',
            'store_id' => $this->store->id,
            'stock_opname_id' => $this->stockOpname->id,
            'request_type' => 'Regular',
            'status' => ItemRequest::STATUS_SUBMITTED,
            'delete_flag' => false
        ]);

        // Create temporary SPB for the same stock opname - should be allowed
        $response = $this->json('POST', route('item_requests.store'), [
            'store_id' => $this->store->id,
            'stock_opname_id' => $this->stockOpname->id,
            'request_type' => 'Temporary',
            'request_date' => Carbon::now()->format('Y-m-d')
        ]);

        $response->assertStatus(200);
        $response->assertJson(['success']);
    }
}