<?php

/**
 * 文件功能：聊天消息模型
 *
 * 对应原 ASP 文件：内存 Application("_says") 变量 (用数据库做持久化归档)
 *
 * @author   ChatRoom Laravel
 *
 * @version  1.0.0
 */

namespace App\Models;

use Illuminate\Database\Eloquent\Model;

/**
 * 聊天消息模型
 * 负责承载聊天室文本消息、图片消息与过期图片占位消息。
 */
class Message extends Model
{
    public const RETENTION_USER_CHAT = 'user_chat';

    public const RETENTION_SYSTEM_NOTICE = 'system_notice';

    public const RETENTION_GAME_NOTICE = 'game_notice';

    public const RETENTION_EPHEMERAL_NOTICE = 'ephemeral_notice';

    /**
     * 可按过期策略清理的消息保留类型。
     *
     * @return array<int, string>
     */
    public static function purgableRetentionTypes(): array
    {
        return [
            self::RETENTION_GAME_NOTICE,
            self::RETENTION_EPHEMERAL_NOTICE,
        ];
    }

    /**
     * 根据广播消息载荷推断数据库保留类型。
     *
     * @param  array<string, mixed>  $messageData  聊天室消息载荷
     */
    public static function resolveRetentionType(array $messageData): string
    {
        $explicitType = (string) ($messageData['retention_type'] ?? '');
        if (in_array($explicitType, [
            self::RETENTION_USER_CHAT,
            self::RETENTION_SYSTEM_NOTICE,
            self::RETENTION_GAME_NOTICE,
            self::RETENTION_EPHEMERAL_NOTICE,
        ], true)) {
            return $explicitType;
        }

        $fromUser = (string) ($messageData['from_user'] ?? '');
        $action = (string) ($messageData['action'] ?? '');
        $messageType = (string) ($messageData['message_type'] ?? 'text');

        if (self::isEphemeralNotice($fromUser, $action)) {
            return self::RETENTION_EPHEMERAL_NOTICE;
        }

        if (self::isGameNotice($fromUser, $action, $messageType, $messageData)) {
            return self::RETENTION_GAME_NOTICE;
        }

        if (self::isSystemNotice($fromUser)) {
            return self::RETENTION_SYSTEM_NOTICE;
        }

        return self::RETENTION_USER_CHAT;
    }

    /**
     * 判断消息是否属于可短期保留的进出场类通知。
     */
    public static function isEphemeralNotice(string $fromUser, string $action = ''): bool
    {
        return in_array($fromUser, ['进出播报', '座驾播报'], true)
            || in_array($action, ['system_welcome', 'vip_presence', 'ride_presence', 'auto_save_exp'], true);
    }

    /**
     * 判断消息是否属于游戏或玩法通知。
     *
     * @param  array<string, mixed>  $messageData  聊天室消息载荷
     */
    public static function isGameNotice(string $fromUser, string $action, string $messageType = 'text', array $messageData = []): bool
    {
        $gameSenders = ['钓鱼播报', '星海小博士'];
        $gameActions = [
            'fishing_result',
            'idiom_result',
            'riddle_result',
            'ride_purchase',
        ];

        if (in_array($fromUser, $gameSenders, true) || in_array($action, $gameActions, true)) {
            return true;
        }

        if (isset($messageData['toast_notification'])) {
            $title = (string) data_get($messageData, 'toast_notification.title', '');

            return str_contains($title, '下注')
                || str_contains($title, '赛马')
                || str_contains($title, '百家乐')
                || str_contains($title, '双色球')
                || str_contains($title, '红包')
                || str_contains($title, '结算');
        }

        return in_array($messageType, ['game_notice'], true);
    }

    /**
     * 判断消息是否来自系统发送者。
     */
    public static function isSystemNotice(string $fromUser): bool
    {
        return in_array($fromUser, [
            '系统',
            '系统公告',
            '系统传音',
            '系统播报',
            '送花播报',
            'AI小班长',
        ], true);
    }

    /**
     * The attributes that are mass assignable.
     *
     * @var array<int, string>
     */
    protected $fillable = [
        'room_id',
        'from_user',
        'to_user',
        'content',
        'is_secret',
        'font_color',
        'action',
        'message_type',
        'image_path',
        'image_thumb_path',
        'image_original_name',
        'retention_type',
        'sent_at',
    ];

    /**
     * 返回模型字段的类型转换配置。
     *
     * @return array<string, string>
     */
    protected function casts(): array
    {
        return [
            'sent_at' => 'datetime',
            'is_secret' => 'boolean',
        ];
    }
}
