<?php

/**
 * 文件功能：VIP 会员等级模型
 * 存储会员名称、图标、颜色、倍率、专属进入/离开模板
 * 后台可完整 CRUD 管理
 *
 * @author   ChatRoom Laravel
 *
 * @version  1.0.0
 */

namespace App\Models;

use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\HasMany;

class VipLevel extends Model
{
    use HasFactory;

    /**
     * 会员进退场支持的特效选项。
     *
     * @var array<int, string>
     */
    public const EFFECT_OPTIONS = [
        'none',
        'fireworks',
        'rain',
        'lightning',
        'snow',
        'sakura',
        'meteors',
        'gold-rain',
        'hearts',
        'confetti',
        'fireflies',
    ];

    /**
     * 会员进退场支持的横幅风格选项。
     *
     * @var array<int, string>
     */
    public const BANNER_STYLE_OPTIONS = [
        'aurora',
        'storm',
        'royal',
        'cosmic',
        'farewell',
    ];

    /** @var string 表名 */
    protected $table = 'vip_levels';

    /** @var array 可批量赋值字段 */
    protected $fillable = [
        'name',
        'icon',
        'color',
        'exp_multiplier',
        'jjb_multiplier',
        'join_templates',
        'leave_templates',
        'join_effect',
        'leave_effect',
        'join_banner_style',
        'leave_banner_style',
        'allow_custom_messages',
        'sort_order',
        'price',
        'duration_days',
    ];

    /** @var array 类型转换 */
    protected $casts = [
        'exp_multiplier' => 'float',
        'jjb_multiplier' => 'float',
        'sort_order' => 'integer',
        'price' => 'float',
        'duration_days' => 'integer',
        'allow_custom_messages' => 'boolean',
    ];

    /**
     * 判断当前等级是否高于指定等级。
     * 依靠 sort_order 判断。
     */
    public function isHigherThan(self|int|null $other): bool
    {
        if ($other === null) {
            return true;
        }

        $otherOrder = ($other instanceof self)
            ? $other->sort_order
            : self::where('id', $other)->value('sort_order') ?? 0;

        return $this->sort_order > $otherOrder;
    }

    /**
     * 计算相对于另一个等级的差价。
     * 如果当前等级价格更低，则返回 0。
     */
    public function getUpgradePrice(self|int|null $other): float
    {
        if ($other === null) {
            return (float) $this->price;
        }

        $otherPrice = ($other instanceof self)
            ? (float) $other->price
            : (float) (self::where('id', $other)->value('price') ?? 0);

        $diff = (float) $this->price - $otherPrice;

        return max(0.0, $diff);
    }

    /**
     * 关联：该等级下的所有用户
     */
    public function users(): HasMany
    {
        return $this->hasMany(User::class, 'vip_level_id');
    }

    /**
     * 获取进入聊天室的专属欢迎语模板数组
     */
    public function getJoinTemplatesArrayAttribute(): array
    {
        if (empty($this->join_templates)) {
            return [];
        }

        $decoded = json_decode($this->join_templates, true);

        return is_array($decoded) ? $decoded : [];
    }

    /**
     * 获取离开聊天室的专属提示语模板数组
     */
    public function getLeaveTemplatesArrayAttribute(): array
    {
        if (empty($this->leave_templates)) {
            return [];
        }

        $decoded = json_decode($this->leave_templates, true);

        return is_array($decoded) ? $decoded : [];
    }

    /**
     * 从模板数组中随机选一条，替换 {username} 占位符
     *
     * @param  array  $templates  模板数组
     * @param  string  $username  用户名
     */
    public static function renderTemplate(array $templates, string $username): ?string
    {
        if (empty($templates)) {
            return null;
        }

        $template = $templates[array_rand($templates)];

        return str_replace('{username}', $username, $template);
    }

    /**
     * 获取规范化后的入场特效键名。
     */
    public function joinEffectKey(): string
    {
        return in_array($this->join_effect, self::EFFECT_OPTIONS, true)
            ? (string) $this->join_effect
            : 'none';
    }

    /**
     * 获取规范化后的离场特效键名。
     */
    public function leaveEffectKey(): string
    {
        return in_array($this->leave_effect, self::EFFECT_OPTIONS, true)
            ? (string) $this->leave_effect
            : 'none';
    }

    /**
     * 获取规范化后的入场横幅风格键名。
     */
    public function joinBannerStyleKey(): string
    {
        return in_array($this->join_banner_style, self::BANNER_STYLE_OPTIONS, true)
            ? (string) $this->join_banner_style
            : 'aurora';
    }

    /**
     * 获取规范化后的离场横幅风格键名。
     */
    public function leaveBannerStyleKey(): string
    {
        return in_array($this->leave_banner_style, self::BANNER_STYLE_OPTIONS, true)
            ? (string) $this->leave_banner_style
            : 'farewell';
    }
}
