<?php

/**
 * 文件功能：AI小班长资金调度服务
 *
 * 统一维护 AI小班长的银行存取与阶段性理财里程碑公告，
 * 常规场景下仅在手上金币超过 100 万时自动存银行，
 * 特殊场景（如买单活动的大额下注）才会动用银行资产。
 */

namespace App\Services;

use App\Events\MessageSent;
use App\Jobs\SaveMessageJob;
use App\Models\BankLog;
use App\Models\User;
use Illuminate\Support\Facades\DB;

/**
 * 负责 AI小班长的常规存款、大额调款与里程碑播报。
 */
class AiFinanceService
{
    /**
     * AI小班长手上需要保留的最低可用金币。
     */
    public const AVAILABLE_GOLD_RESERVE = 1000000;

    /**
     * 银行存款的阶段性目标。
     *
     * @var list<int>
     */
    private const BANK_MILESTONES = [
        10000000,
        30000000,
    ];

    /**
     * 注入聊天室状态服务，用于里程碑公告广播。
     */
    public function __construct(
        private readonly ChatStateService $chatState,
    ) {}

    /**
     * 计算 AI 当前手上可直接使用的金币。
     */
    public function getSpendableGold(User $user): int
    {
        return (int) ($user->jjb ?? 0);
    }

    /**
     * 计算 AI 当前持有的金币总资产（手上 + 银行）。
     */
    public function getTotalGoldAssets(User $user): int
    {
        return (int) ($user->jjb ?? 0) + (int) ($user->bank_jjb ?? 0);
    }

    /**
     * 判断 AI 当前手上金币是否足够支付本次支出。
     */
    public function prepareSpend(User $user, int $spendAmount): bool
    {
        if ($spendAmount <= 0) {
            return true;
        }

        $user->refresh();

        return (int) ($user->jjb ?? 0) >= $spendAmount;
    }

    /**
     * 为大额支出准备手头金币。
     *
     * 该模式不会保留手上余额阈值，适用于买单活动等需要临时调拨银行金币的场景。
     */
    public function prepareAllInSpend(User $user, int $spendAmount): bool
    {
        if ($spendAmount <= 0) {
            return true;
        }

        return $this->raiseWalletTo($user, $spendAmount);
    }

    /**
     * 将 100 万以上的富余金币自动转存到银行。
     */
    public function bankExcessGold(User $user): void
    {
        $milestones = DB::transaction(function () use ($user): array {
            $lockedUser = User::query()->lockForUpdate()->find($user->id);
            if (! $lockedUser) {
                return [];
            }

            $walletGold = (int) ($lockedUser->jjb ?? 0);
            if ($walletGold <= self::AVAILABLE_GOLD_RESERVE) {
                return [];
            }

            $bankBefore = (int) ($lockedUser->bank_jjb ?? 0);
            $depositAmount = $walletGold - self::AVAILABLE_GOLD_RESERVE;

            // 只把超过 100 万的部分转入银行，手上保留不高于 100 万的常规活动资金。
            $lockedUser->jjb = self::AVAILABLE_GOLD_RESERVE;
            $lockedUser->bank_jjb = $bankBefore + $depositAmount;
            $lockedUser->save();

            BankLog::create([
                'user_id' => $lockedUser->id,
                'type' => 'deposit',
                'amount' => $depositAmount,
                'balance_after' => (int) $lockedUser->bank_jjb,
            ]);

            return array_values(array_filter(
                self::BANK_MILESTONES,
                fn (int $milestone): bool => $bankBefore < $milestone && (int) $lockedUser->bank_jjb >= $milestone,
            ));
        });

        $user->refresh();

        foreach ($milestones as $milestone) {
            $this->broadcastMilestoneAnnouncement($milestone);
        }
    }

    /**
     * 一次性完成 AI 常规理财：仅把超过 100 万的部分转入银行。
     */
    public function rebalanceHoldings(User $user): void
    {
        $this->bankExcessGold($user);
    }

    /**
     * 将手上金币抬升到目标值，必要时从银行自动取款。
     */
    private function raiseWalletTo(User $user, int $targetWalletGold): bool
    {
        $reachedTarget = DB::transaction(function () use ($user, $targetWalletGold): bool {
            $lockedUser = User::query()->lockForUpdate()->find($user->id);
            if (! $lockedUser) {
                return false;
            }

            $walletGold = (int) ($lockedUser->jjb ?? 0);
            if ($walletGold >= $targetWalletGold) {
                return true;
            }

            $bankGold = (int) ($lockedUser->bank_jjb ?? 0);
            $withdrawAmount = min($targetWalletGold - $walletGold, $bankGold);
            if ($withdrawAmount <= 0) {
                return false;
            }

            // 优先把银行金币提回手上，保证 AI 的即时可用余额尽量回到目标线。
            $lockedUser->jjb = $walletGold + $withdrawAmount;
            $lockedUser->bank_jjb = $bankGold - $withdrawAmount;
            $lockedUser->save();

            BankLog::create([
                'user_id' => $lockedUser->id,
                'type' => 'withdraw',
                'amount' => $withdrawAmount,
                'balance_after' => (int) $lockedUser->bank_jjb,
            ]);

            return (int) $lockedUser->jjb >= $targetWalletGold;
        });

        $user->refresh();

        return $reachedTarget;
    }

    /**
     * 广播 AI小班长达成银行存款目标的全站公告。
     */
    private function broadcastMilestoneAnnouncement(int $milestone): void
    {
        $roomIds = $this->chatState->getAllActiveRoomIds();
        if (empty($roomIds)) {
            $roomIds = [1];
        }

        $milestoneInWan = (int) ($milestone / 10000);
        $content = "🏆 🎉 <b>【全站公告】</b> 恭喜 <b>AI小班长</b> 达成理财新高度！<br/>他在银行的存款已成功突破 <span style='color:#e11d48;font-weight:bold;'>{$milestoneInWan}万</span> 金币！💰✨";

        foreach ($roomIds as $roomId) {
            $message = [
                'id' => $this->chatState->nextMessageId($roomId),
                'room_id' => $roomId,
                'from_user' => '系统传音',
                'to_user' => '大家',
                'content' => $content,
                'is_secret' => false,
                'font_color' => '#f59e0b',
                'action' => '大声宣告',
                'sent_at' => now()->toDateTimeString(),
            ];

            $this->chatState->pushMessage($roomId, $message);
            broadcast(new MessageSent($roomId, $message));
            SaveMessageJob::dispatch($message);
        }
    }
}
