<?php

namespace Tests\Feature;

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

class NumberingFormatsControllerTest extends TestCase
{
    use RefreshDatabase;

    protected $user;
    protected $store;

    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
        ]);
    }

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

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

        $response->assertStatus(200);
        $response->assertViewIs('m-numbering-formats.index');
        $response->assertViewHas('variables');
    }

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

        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' => 5,
            'is_active' => true,
            'delete_flag' => false
        ]);

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

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

    /** @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
        ]);

        NumberingFormat::create([
            'store_id' => $this->store->id,
            'document_type' => 'SPB',
            'format_pattern' => '{DOCTYPE}{NUMBER}',
            'number_length' => 4,
            'reset_period' => 'Never',
            'is_active' => true,
            'delete_flag' => false
        ]);

        NumberingFormat::create([
            'store_id' => $anotherStore->id,
            'document_type' => 'SO',
            'format_pattern' => '{DOCTYPE}{NUMBER}',
            'number_length' => 4,
            'reset_period' => 'Never',
            'is_active' => true,
            'delete_flag' => false
        ]);

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

        $response->assertStatus(200);
        $data = $response->json('data');
        $this->assertCount(1, $data);
    }

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

        NumberingFormat::create([
            'store_id' => $this->store->id,
            'document_type' => 'SPB',
            'format_pattern' => '{DOCTYPE}{NUMBER}',
            'number_length' => 4,
            'reset_period' => 'Never',
            'is_active' => true,
            'delete_flag' => false
        ]);

        NumberingFormat::create([
            'store_id' => $this->store->id,
            'document_type' => 'SO',
            'format_pattern' => '{DOCTYPE}{NUMBER}',
            'number_length' => 4,
            'reset_period' => 'Never',
            'is_active' => true,
            'delete_flag' => false
        ]);

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

        $response->assertStatus(200);
        $data = $response->json('data');
        $this->assertCount(1, $data);
    }

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

        NumberingFormat::create([
            'store_id' => $this->store->id,
            'document_type' => 'SPB',
            'format_pattern' => '{DOCTYPE}{NUMBER}',
            'number_length' => 4,
            'reset_period' => 'Never',
            'is_active' => true,
            'delete_flag' => false
        ]);

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

        $response->assertStatus(200);
        $data = $response->json('data');
        $this->assertCount(1, $data);
    }

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

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

        $response->assertStatus(200);
        $response->assertViewIs('m-numbering-formats.form');
        $response->assertViewHas('data');
        $response->assertViewHas('variables');
    }

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

        $formatData = [
            'store_id' => $this->store->id,
            'document_type' => 'SPB',
            'format_pattern' => '{DOCTYPE}{SEP}{STORE}{SEP}{YY}{MM}{SEP}{NUMBER}',
            'prefix' => 'SPB',
            'separator' => '-',
            'number_length' => 4,
            'reset_period' => 'Monthly',
            'current_number' => 0,
            'is_active' => true
        ];

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

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

        $this->assertDatabaseHas('m_numbering_formats', [
            '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',
            'is_active' => true,
            'delete_flag' => false
        ]);
    }

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

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

        $response->assertStatus(422);
        $response->assertJsonValidationErrors([
            'store_id',
            'document_type',
            'format_pattern',
            'number_length',
            'reset_period'
        ]);
    }

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

        $response = $this->json('POST', route('numbering_formats.store'), [
            'store_id' => 99999,
            'document_type' => 'SPB',
            'format_pattern' => '{DOCTYPE}{NUMBER}',
            'number_length' => 4,
            'reset_period' => 'Never'
        ]);

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

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

        $response = $this->json('POST', route('numbering_formats.store'), [
            'store_id' => $this->store->id,
            'document_type' => 'INVALID',
            'format_pattern' => '{DOCTYPE}{NUMBER}',
            'number_length' => 4,
            'reset_period' => 'Never'
        ]);

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

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

        // Create first format
        NumberingFormat::create([
            'store_id' => $this->store->id,
            'document_type' => 'SPB',
            'format_pattern' => '{DOCTYPE}{NUMBER}',
            'number_length' => 4,
            'reset_period' => 'Never',
            'is_active' => true,
            'delete_flag' => false
        ]);

        // Try to create duplicate
        $response = $this->json('POST', route('numbering_formats.store'), [
            'store_id' => $this->store->id,
            'document_type' => 'SPB',
            'format_pattern' => '{DOCTYPE}{NUMBER}',
            'number_length' => 4,
            'reset_period' => 'Never'
        ]);

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

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

        $format = NumberingFormat::create([
            'store_id' => $this->store->id,
            'document_type' => 'SPB',
            'format_pattern' => '{DOCTYPE}{NUMBER}',
            'number_length' => 4,
            'reset_period' => 'Never',
            'is_active' => true,
            'delete_flag' => false
        ]);

        $response = $this->get(route('numbering_formats.edit', $format));

        $response->assertStatus(200);
        $response->assertViewIs('m-numbering-formats.form');
        $response->assertViewHas('data', $format);
    }

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

        $format = NumberingFormat::create([
            'store_id' => $this->store->id,
            'document_type' => 'SPB',
            'format_pattern' => '{DOCTYPE}{NUMBER}',
            'number_length' => 4,
            'reset_period' => 'Never',
            'is_active' => true,
            'delete_flag' => false
        ]);

        $updateData = [
            'store_id' => $this->store->id,
            'document_type' => 'SPB',
            'format_pattern' => '{DOCTYPE}{SEP}{STORE}{SEP}{NUMBER}',
            'separator' => '-',
            'number_length' => 5,
            'reset_period' => 'Monthly',
            'current_number' => 10,
            'is_active' => false
        ];

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

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

        $format->refresh();
        $this->assertEquals('{DOCTYPE}{SEP}{STORE}{SEP}{NUMBER}', $format->format_pattern);
        $this->assertEquals(5, $format->number_length);
        $this->assertEquals('Monthly', $format->reset_period);
        $this->assertFalse($format->is_active);
    }

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

        $format = NumberingFormat::create([
            'store_id' => $this->store->id,
            'document_type' => 'SPB',
            'format_pattern' => '{DOCTYPE}{NUMBER}',
            'number_length' => 4,
            'reset_period' => 'Never',
            'is_active' => true,
            'delete_flag' => false,
            'created_by' => $this->user->id
        ]);

        $response = $this->get(route('numbering_formats.show', $format));

        $response->assertStatus(200);
        $response->assertViewIs('m-numbering-formats.show');
        $response->assertViewHas('data', $format);
    }

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

        $format = NumberingFormat::create([
            'store_id' => $this->store->id,
            'document_type' => 'SPB',
            'format_pattern' => '{DOCTYPE}{NUMBER}',
            'number_length' => 4,
            'reset_period' => 'Never',
            'is_active' => true,
            'delete_flag' => false
        ]);

        $response = $this->delete(route('numbering_formats.destroy', $format));

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

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

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

        $response = $this->json('GET', route('numbering_formats.preview'), [
            'pattern' => '{DOCTYPE}{SEP}{STORE}{SEP}{NUMBER}',
            'store_id' => $this->store->id,
            'document_type' => 'SPB',
            'separator' => '-',
            'number_length' => 4,
            'sample_number' => 123
        ]);

        $response->assertStatus(200);
        $response->assertJsonStructure([
            'preview',
            'pattern',
            'sample_number'
        ]);

        $preview = $response->json('preview');
        $this->assertStringContainsString('SPB', $preview);
        $this->assertStringContainsString('TST001', $preview);
        $this->assertStringContainsString('0123', $preview);
    }

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

        $response = $this->json('GET', route('numbering_formats.preview'), [
            'pattern' => '{DOCTYPE}{NUMBER}'
            // Missing store_id and document_type
        ]);

        $response->assertStatus(400);
        $response->assertJson(['error' => 'Missing required parameters']);
    }

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

        NumberingFormat::create([
            'store_id' => $this->store->id,
            'document_type' => 'SPB',
            'format_pattern' => '{DOCTYPE}{SEP}{STORE}{SEP}{NUMBER}',
            'separator' => '-',
            'number_length' => 4,
            'reset_period' => 'Never',
            'current_number' => 5,
            'is_active' => true,
            'delete_flag' => false
        ]);

        $response = $this->json('POST', route('numbering_formats.generate'), [
            'store_id' => $this->store->id,
            'document_type' => 'SPB'
        ]);

        $response->assertStatus(200);
        $response->assertJsonStructure([
            'number',
            'store_id',
            'document_type'
        ]);

        $number = $response->json('number');
        $this->assertStringContainsString('SPB', $number);
        $this->assertStringContainsString('TST001', $number);
    }

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

        $response = $this->json('POST', route('numbering_formats.generate'), [
            'store_id' => $this->store->id
            // Missing document_type
        ]);

        $response->assertStatus(400);
        $response->assertJson(['error' => 'store_id and document_type required']);
    }

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

        $format = NumberingFormat::create([
            'store_id' => $this->store->id,
            'document_type' => 'SPB',
            'format_pattern' => '{DOCTYPE}{NUMBER}',
            'number_length' => 4,
            'reset_period' => 'Monthly',
            'current_number' => 50,
            'is_active' => true,
            'delete_flag' => false
        ]);

        $response = $this->json('POST', route('numbering_formats.reset', $format));

        $response->assertStatus(200);
        $response->assertJson([
            'success' => true,
            'message' => 'Counter reset successfully'
        ]);

        $format->refresh();
        $this->assertEquals(0, $format->current_number);
        $this->assertEquals(now()->format('Y-m-d'), $format->last_reset_date->format('Y-m-d'));
    }

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

        $response = $this->json('POST', route('numbering_formats.generate'), [
            'store_id' => $this->store->id,
            'document_type' => 'SPB'
        ]);

        $response->assertStatus(200);
        
        // Check that a format was created
        $this->assertDatabaseHas('m_numbering_formats', [
            'store_id' => $this->store->id,
            'document_type' => 'SPB',
            'delete_flag' => false
        ]);
    }
}