<?php

/**
 * 文件功能：聊天室发言请求验证器
 *
 * @author   ChatRoom Laravel
 *
 * @version  1.0.0
 */

namespace App\Http\Requests;

use Illuminate\Contracts\Validation\Validator;
use Illuminate\Foundation\Http\FormRequest;
use Illuminate\Http\Exceptions\HttpResponseException;
use Illuminate\Validation\Rule;

/**
 * 聊天室发言请求验证器
 * 负责统一校验文本消息与图片消息的发送参数。
 */
class SendMessageRequest extends FormRequest
{
    /**
     * 允许前端提交的发言动作白名单。
     */
    private const ALLOWED_ACTIONS = [
        '',
        '微笑',
        '大笑',
        '愤怒',
        '哭泣',
        '害羞',
        '鄙视',
        '得意',
        '疑惑',
        '同情',
        '无奈',
        '拳打',
        '飞吻',
        '偷看',
        '欢迎',
    ];

    /**
     * 判断当前请求是否允许继续。
     */
    public function authorize(): bool
    {
        return true; // 权限验证已交由中间件处理
    }

    /**
     * 返回发言请求的校验规则。
     *
     * @return array<string, \Illuminate\Contracts\Validation\ValidationRule|array<int, mixed>|string>
     */
    public function rules(): array
    {
        return [
            'content' => ['nullable', 'required_without:image', 'string', 'max:500'], // 文本与图片至少二选一
            'image' => ['nullable', 'required_without:content', 'file', 'image', 'mimes:jpeg,png,jpg,gif,webp', 'max:6144'],
            'to_user' => ['nullable', 'string', 'max:50'],
            'is_secret' => ['nullable', 'boolean'],
            'font_color' => ['nullable', 'string', 'regex:/^#[0-9a-fA-F]{6}$/'],   // html color hex
            'action' => ['nullable', 'string', 'max:50', Rule::in(self::ALLOWED_ACTIONS)],   // 动作字段仅允许预设值，阻断拼接式 XSS 注入
        ];
    }

    /**
     * 在校验前统一整理输入，避免首尾空白绕过白名单判断。
     */
    protected function prepareForValidation(): void
    {
        $action = $this->input('action');

        $this->merge([
            'action' => is_string($action) ? trim($action) : $action,
        ]);
    }

    /**
     * 返回校验失败时的中文提示。
     */
    public function messages(): array
    {
        return [
            'content.required_without' => '文字内容和图片至少要发送一项。',
            'content.max' => '发言内容不能超过 500 个字符。',
            'image.required_without' => '文字内容和图片至少要发送一项。',
            'image.image' => '上传的文件必须是图片。',
            'image.mimes' => '仅支持 jpg、jpeg、png、gif、webp 图片格式。',
            'image.max' => '图片大小不能超过 6MB。',
            'font_color.regex' => '发言颜色格式不合法，请重新选择颜色。',
            'action.in' => '发言动作不合法，请重新选择。',
        ];
    }

    /**
     * 重写验证失败的处理，无论如何（就算未按 ajax 标准提交）都必须抛出 JSON，不可以触发网页重定向去走 GET 请求而引发 302 方法错误
     */
    protected function failedValidation(Validator $validator): void
    {
        throw new HttpResponseException(response()->json([
            'status' => 'error',
            'message' => $validator->errors()->first(),
            'errors' => $validator->errors(),
        ], 422));
    }
}
