<?php

namespace Tests\Feature\Modules;

use Tests\TestCase;
use App\Modules\ContentModule;
use App\Services\Core\ModuleManager;
use App\Services\Core\EventBus;
use App\Services\Core\ConfigurationManager;
use App\DTOs\TelegramUpdateDTO;
use App\Models\User;
use App\Models\Content;
use App\Models\Menu;
use Illuminate\Foundation\Testing\RefreshDatabase;
use Mockery;

class ContentModuleTest extends TestCase
{
    use RefreshDatabase;

    private ContentModule $module;
    private $mockModuleManager;
    private $mockEventBus;
    private $mockConfigManager;

    protected function setUp(): void
    {
        parent::setUp();
        
        $this->mockModuleManager = Mockery::mock(ModuleManager::class);
        $this->mockEventBus = Mockery::mock(EventBus::class);
        $this->mockConfigManager = Mockery::mock(ConfigurationManager::class);
        
        $this->module = new ContentModule(
            $this->mockModuleManager,
            $this->mockEventBus,
            $this->mockConfigManager
        );
    }

    protected function tearDown(): void
    {
        Mockery::close();
        parent::tearDown();
    }

    public function test_module_registration()
    {
        $this->assertEquals('ContentModule', $this->module->getName());
        $this->assertEquals('1.0.0', $this->module->getVersion());
        $this->assertNotEmpty($this->module->getDescription());
        $this->assertContains('/help', $this->module->getHandledCommands());
        $this->assertContains('/about', $this->module->getHandledCommands());
        $this->assertContains('/menu', $this->module->getHandledCommands());
    }

    public function test_handles_help_command()
    {
        $user = User::factory()->create(['telegram_id' => 67890]);
        
        $updateData = [
            'message' => [
                'text' => '/help',
                'chat' => ['id' => 12345],
                'from' => ['id' => 67890, 'first_name' => 'Test']
            ]
        ];

        $update = TelegramUpdateDTO::fromArray($updateData);

        $this->mockEventBus->shouldReceive('dispatch')
            ->with('telegram.send_message', Mockery::any())
            ->once();

        $result = $this->module->handleUpdate($update);
        $this->assertTrue($result);
    }

    public function test_handles_about_command()
    {
        $user = User::factory()->create(['telegram_id' => 67890]);
        
        Content::factory()->create([
            'key' => 'about',
            'type' => 'text',
            'content' => 'About our bot',
            'is_active' => true
        ]);
        
        $updateData = [
            'message' => [
                'text' => '/about',
                'chat' => ['id' => 12345],
                'from' => ['id' => 67890, 'first_name' => 'Test']
            ]
        ];

        $update = TelegramUpdateDTO::fromArray($updateData);

        $this->mockEventBus->shouldReceive('dispatch')
            ->with('telegram.send_message', Mockery::any())
            ->once();

        $result = $this->module->handleUpdate($update);
        $this->assertTrue($result);
    }

    public function test_handles_menu_command()
    {
        $user = User::factory()->create(['telegram_id' => 67890]);
        
        Menu::factory()->create([
            'name' => 'Main Menu',
            'type' => 'inline',
            'is_active' => true,
            'items' => [
                [
                    'text' => 'Help',
                    'type' => 'command',
                    'action' => '/help'
                ],
                [
                    'text' => 'About',
                    'type' => 'command',  
                    'action' => '/about'
                ]
            ]
        ]);
        
        $updateData = [
            'message' => [
                'text' => '/menu',
                'chat' => ['id' => 12345],
                'from' => ['id' => 67890, 'first_name' => 'Test']
            ]
        ];

        $update = TelegramUpdateDTO::fromArray($updateData);

        $this->mockEventBus->shouldReceive('dispatch')
            ->with('telegram.send_message', Mockery::any())
            ->once();

        $result = $this->module->handleUpdate($update);
        $this->assertTrue($result);
    }

    public function test_handles_content_callback()
    {
        $user = User::factory()->create(['telegram_id' => 67890]);
        
        Content::factory()->create([
            'key' => 'privacy',
            'type' => 'text',
            'content' => 'Privacy policy content',
            'is_active' => true
        ]);
        
        $updateData = [
            'callback_query' => [
                'data' => 'content_privacy',
                'message' => [
                    'chat' => ['id' => 12345],
                    'message_id' => 123
                ],
                'from' => ['id' => 67890, 'first_name' => 'Test']
            ]
        ];

        $update = TelegramUpdateDTO::fromArray($updateData);

        $this->mockEventBus->shouldReceive('dispatch')
            ->with('telegram.edit_message', Mockery::any())
            ->once();

        $result = $this->module->handleCallback($update);
        $this->assertTrue($result);
    }

    public function test_handles_menu_callback()
    {
        $user = User::factory()->create(['telegram_id' => 67890]);
        
        Menu::factory()->create([
            'id' => 1,
            'name' => 'Settings Menu',
            'type' => 'inline',
            'is_active' => true,
            'items' => [
                [
                    'text' => 'Language',
                    'type' => 'callback',
                    'action' => 'lang_menu'
                ]
            ]
        ]);
        
        $updateData = [
            'callback_query' => [
                'data' => 'menu_1',
                'message' => [
                    'chat' => ['id' => 12345],
                    'message_id' => 123
                ],
                'from' => ['id' => 67890, 'first_name' => 'Test']
            ]
        ];

        $update = TelegramUpdateDTO::fromArray($updateData);

        $this->mockEventBus->shouldReceive('dispatch')
            ->with('telegram.edit_message', Mockery::any())
            ->once();

        $result = $this->module->handleCallback($update);
        $this->assertTrue($result);
    }

    public function test_dynamic_content_rendering()
    {
        $user = User::factory()->create(['telegram_id' => 67890, 'first_name' => 'John']);
        
        Content::factory()->create([
            'key' => 'welcome',
            'type' => 'text',
            'content' => 'Welcome {{user.first_name}}! You have {{user.balance}} credits.',
            'is_active' => true
        ]);

        $content = $this->module->renderContent('welcome', $user);
        
        $this->assertStringContains('Welcome John!', $content);
        $this->assertStringContains('You have', $content);
    }

    public function test_multilingual_content()
    {
        $user = User::factory()->create(['telegram_id' => 67890]);
        
        Content::factory()->create([
            'key' => 'greeting',
            'type' => 'text',
            'content' => json_encode([
                'en' => 'Hello!',
                'fa' => 'سلام!'
            ]),
            'is_active' => true
        ]);

        $this->mockConfigManager->shouldReceive('get')
            ->with('user.67890.language', 'fa')
            ->andReturn('fa');

        $content = $this->module->getLocalizedContent('greeting', $user);
        $this->assertEquals('سلام!', $content);
    }

    public function test_handles_image_content()
    {
        $user = User::factory()->create(['telegram_id' => 67890]);
        
        Content::factory()->create([
            'key' => 'banner',
            'type' => 'image',
            'content' => 'https://example.com/image.jpg',
            'metadata' => json_encode(['caption' => 'Welcome banner']),
            'is_active' => true
        ]);
        
        $updateData = [
            'callback_query' => [
                'data' => 'content_banner',
                'message' => [
                    'chat' => ['id' => 12345],
                    'message_id' => 123
                ],
                'from' => ['id' => 67890, 'first_name' => 'Test']
            ]
        ];

        $update = TelegramUpdateDTO::fromArray($updateData);

        $this->mockEventBus->shouldReceive('dispatch')
            ->with('telegram.send_photo', Mockery::any())
            ->once();

        $result = $this->module->handleCallback($update);
        $this->assertTrue($result);
    }

    public function test_handles_video_content()
    {
        $user = User::factory()->create(['telegram_id' => 67890]);
        
        Content::factory()->create([
            'key' => 'tutorial',
            'type' => 'video',
            'content' => 'https://example.com/video.mp4',
            'metadata' => json_encode(['caption' => 'Tutorial video']),
            'is_active' => true
        ]);
        
        $updateData = [
            'callback_query' => [
                'data' => 'content_tutorial',
                'message' => [
                    'chat' => ['id' => 12345],
                    'message_id' => 123
                ],
                'from' => ['id' => 67890, 'first_name' => 'Test']
            ]
        ];

        $update = TelegramUpdateDTO::fromArray($updateData);

        $this->mockEventBus->shouldReceive('dispatch')
            ->with('telegram.send_video', Mockery::any())
            ->once();

        $result = $this->module->handleCallback($update);
        $this->assertTrue($result);
    }

    public function test_keyboard_menu_generation()
    {
        Menu::factory()->create([
            'name' => 'Main Keyboard',
            'type' => 'keyboard',
            'is_active' => true,
            'items' => [
                [
                    'text' => 'Help',
                    'type' => 'command',
                    'action' => '/help',
                    'row' => 0,
                    'column' => 0
                ],
                [
                    'text' => 'Settings',
                    'type' => 'command',
                    'action' => '/settings',
                    'row' => 0,
                    'column' => 1
                ],
                [
                    'text' => 'About',
                    'type' => 'command',
                    'action' => '/about',
                    'row' => 1,
                    'column' => 0
                ]
            ]
        ]);

        $keyboard = $this->module->buildKeyboardMenu('Main Keyboard');
        
        $this->assertIsArray($keyboard);
        $this->assertCount(2, $keyboard); // 2 rows
        $this->assertCount(2, $keyboard[0]); // First row has 2 buttons
        $this->assertCount(1, $keyboard[1]); // Second row has 1 button
    }

    public function test_content_cache()
    {
        Content::factory()->create([
            'key' => 'cached_content',
            'type' => 'text',
            'content' => 'This content should be cached',
            'is_active' => true
        ]);

        // First call should query database
        $content1 = $this->module->getContent('cached_content');
        
        // Second call should use cache
        $content2 = $this->module->getContent('cached_content');
        
        $this->assertEquals($content1, $content2);
        $this->assertEquals('This content should be cached', $content1);
    }

    public function test_module_initialization()
    {
        $this->mockEventBus->shouldReceive('listen')
            ->with('user.created', Mockery::any())
            ->once();

        $this->mockEventBus->shouldReceive('listen')
            ->with('content.updated', Mockery::any())
            ->once();

        $result = $this->module->initialize();
        $this->assertTrue($result);
    }

    public function test_content_not_found()
    {
        $content = $this->module->getContent('non_existent');
        $this->assertNull($content);
    }

    public function test_inactive_content_handling()
    {
        Content::factory()->create([
            'key' => 'inactive_content',
            'type' => 'text',
            'content' => 'This content is inactive',
            'is_active' => false
        ]);

        $content = $this->module->getContent('inactive_content');
        $this->assertNull($content);
    }
}