<?php

namespace App\Events;

use Illuminate\Broadcasting\Channel;
use Illuminate\Queue\SerializesModels;
use Illuminate\Foundation\Events\Dispatchable;
use Illuminate\Broadcasting\InteractsWithSockets;
use Illuminate\Contracts\Broadcasting\ShouldBroadcast;

/**
 * 界面文档 §2.1：`balance.update` —— 钱包余额变动推送。
 *
 * 触发时机：转入/转出/下注/派彩等导致余额变动时。
 * 前端处理：更新余额显示 + Toast 提示。
 */
final class BalanceUpdateBroadcast implements ShouldBroadcast
{
    use Dispatchable, InteractsWithSockets, SerializesModels;

    /** 异步广播队列 */
    public string $queue = 'broadcasts';

    /** 最多重试 3 次 */
    public int $tries = 3;

    /** 单任务超时 10 秒 */
    public int $timeout = 10;

    /**
     * @param  int  $playerId  玩家 ID（用于频道隔离）
     * @param  string  $currencyCode  币种代码
     * @param  int  $balanceMinor  最新余额（最小货币单位）
     * @param  int  $changeMinor  变动金额（最小货币单位，正数为增加，负数为减少）
     * @param  string  $reason  变动原因：transfer_in, transfer_out, bet, prize, refund
     * @param  int  $emittedAtMs  发送时间戳（毫秒）
     */
    public function __construct(
        public readonly int $playerId,
        public readonly string $currencyCode,
        public readonly int $balanceMinor,
        public readonly int $changeMinor,
        public readonly string $reason,
        public readonly int $emittedAtMs,
    ) {}

    /**
     * 使用私有频道，只有指定玩家能收到自己的余额变动。
     *
     * @return array<int, Channel>
     */
    public function broadcastOn(): array
    {
        return [new Channel('player.'.$this->playerId)];
    }

    public function broadcastAs(): string
    {
        return 'balance.update';
    }

    /**
     * @return array{player_id: int, currency_code: string, balance_minor: int, balance_formatted: string, change_minor: int, change_formatted: string, reason: string, emitted_at_ms: int}
     */
    public function broadcastWith(): array
    {
        return [
            'player_id' => $this->playerId,
            'currency_code' => $this->currencyCode,
            'balance_minor' => $this->balanceMinor,
            'balance_formatted' => number_format($this->balanceMinor / 100, 2),
            'change_minor' => $this->changeMinor,
            'change_formatted' => ($this->changeMinor > 0 ? '+' : '').number_format($this->changeMinor / 100, 2),
            'reason' => $this->reason,
            'emitted_at_ms' => $this->emittedAtMs,
        ];
    }
}
