<?php

/**
 * 文件功能：AI小班长聊天控制器测试
 *
 * 覆盖 AI 开关、普通回复、金币福利以及上下文清理逻辑，
 * 同时验证金币福利发放时不会自动动用 AI 的银行存款。
 */

namespace Tests\Feature;

use App\Models\Sysparam;
use App\Models\User;
use App\Services\AiChatService;
use Illuminate\Foundation\Testing\RefreshDatabase;
use Illuminate\Support\Facades\Redis;
use Mockery\MockInterface;
use Tests\TestCase;

/**
 * 验证 AI小班长对话与金币福利接口行为。
 */
class ChatBotControllerTest extends TestCase
{
    use RefreshDatabase;

    /**
     * 每个测试结束后清空 Redis，避免每日奖励计数彼此污染。
     */
    protected function tearDown(): void
    {
        Redis::flushall();
        parent::tearDown();
    }

    /**
     * 默认情况下，AI 功能关闭时应直接拒绝聊天请求。
     */
    public function test_chatbot_disabled_by_default(): void
    {
        $user = User::factory()->create();

        $response = $this->actingAs($user)->postJson(route('chatbot.chat'), [
            'message' => 'Hello',
            'room_id' => 1,
        ]);

        $response->assertStatus(403);
        $response->assertJson(['status' => 'error']);
    }

    /**
     * AI 功能开启后，控制器会返回模型生成的正常回复。
     */
    public function test_chatbot_can_reply(): void
    {
        $user = User::factory()->create();

        Sysparam::updateOrCreate(['alias' => 'chatbot_enabled'], ['body' => '1']);

        User::factory()->create([
            'username' => 'AI小班长',
            'exp_num' => 0,
            'jjb' => 0,
        ]);

        // Mock the AiChatService
        $this->mock(AiChatService::class, function (MockInterface $mock) {
            $mock->shouldReceive('chat')
                ->once()
                ->andReturn([
                    'reply' => 'Hello from AI',
                    'provider' => 'test_provider',
                    'model' => 'test_model',
                ]);
        });

        $response = $this->actingAs($user)->postJson(route('chatbot.chat'), [
            'message' => 'Hello',
            'room_id' => 1,
        ]);

        $response->assertStatus(200);
        $response->assertJson([
            'status' => 'success',
            'reply' => 'Hello from AI',
            'provider' => 'test_provider',
        ]);
    }

    /**
     * 发放金币福利时，只使用 AI 当前手上金币，不会为了凑金额自动动用银行存款。
     */
    public function test_chatbot_can_give_gold(): void
    {
        $user = User::factory()->create(['jjb' => 0]);

        Sysparam::updateOrCreate(['alias' => 'chatbot_enabled'], ['body' => '1']);
        Sysparam::updateOrCreate(['alias' => 'chatbot_max_daily_rewards'], ['body' => '1']);
        Sysparam::updateOrCreate(['alias' => 'chatbot_max_gold'], ['body' => '500']);

        User::factory()->create([
            'username' => 'AI小班长',
            'exp_num' => 0,
            'jjb' => 1000000,
            'bank_jjb' => 1000,
        ]);

        // Mock the AiChatService
        $this->mock(AiChatService::class, function (MockInterface $mock) {
            $mock->shouldReceive('chat')
                ->once()
                ->andReturn([
                    'reply' => 'Here is some gold! [ACTION:GIVE_GOLD]',
                    'provider' => 'test_provider',
                    'model' => 'test_model',
                ]);
        });

        $response = $this->actingAs($user)->postJson(route('chatbot.chat'), [
            'message' => 'Give me gold',
            'room_id' => 1,
        ]);

        $response->assertStatus(200);

        // User should have received gold
        $user->refresh();
        $this->assertGreaterThan(0, $user->jjb);
        $this->assertLessThanOrEqual(500, $user->jjb);

        $aiUser = User::query()->where('username', 'AI小班长')->firstOrFail();
        $this->assertLessThan(1000000, (int) $aiUser->jjb);
        $this->assertSame(1000, (int) $aiUser->bank_jjb);
    }

    /**
     * 用户主动清空上下文时，应调用 AI 服务清理其上下文缓存。
     */
    public function test_clear_context(): void
    {
        $user = User::factory()->create();

        $this->mock(AiChatService::class, function (MockInterface $mock) use ($user) {
            $mock->shouldReceive('clearContext')
                ->once()
                ->with($user->id);
        });

        $response = $this->actingAs($user)->postJson(route('chatbot.clear'));

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