<?php

namespace App\Services\Ticket;

use App\Models\Draw;
use App\Models\RiskPool;
use App\Services\Draw\LotteryHallRealtimeBroadcaster;

/**
 * 风险池占用变化后推送 `risk.warning` / `risk.sold_out`（频道 `lottery-hall`）。
 */
final class RiskPoolRealtimePublisher
{
    private const WARNING_RATIO = 0.8;

    /** @var array<int, string> */
    private array $drawNoById = [];

    public function __construct(
        private readonly LotteryHallRealtimeBroadcaster $hallRealtime,
    ) {}

    public function publishAfterLock(
        int $drawId,
        string $normalizedNumber,
        int $soldOutStatusBefore,
        int $lockedAmountBefore,
        int $totalCapBefore,
        RiskPool $poolAfter,
    ): void {
        $drawNo = $this->resolveDrawNo($drawId);
        $normalizedNumber = strtoupper(trim($normalizedNumber));

        $totalCap = (int) $poolAfter->total_cap_amount;
        if ($totalCap < 1) {
            $totalCap = max(1, $totalCapBefore);
        }

        $soldOutAfter = (int) $poolAfter->sold_out_status;
        if ($soldOutAfter === 1 && $soldOutStatusBefore !== 1) {
            $this->hallRealtime->notifyRiskSoldOut($drawId, $drawNo, $normalizedNumber);
        }

        $lockedAfter = (int) $poolAfter->locked_amount;
        $usageBefore = $totalCapBefore > 0 ? $lockedAmountBefore / $totalCapBefore : 0.0;
        $usageAfter = $totalCap > 0 ? $lockedAfter / $totalCap : 1.0;

        if ($usageAfter >= self::WARNING_RATIO && $usageBefore < self::WARNING_RATIO) {
            $this->hallRealtime->notifyRiskWarning(
                $drawId,
                $drawNo,
                $normalizedNumber,
                $usageAfter,
            );
        }
    }

    public function publishManualSoldOut(Draw $draw, string $normalizedNumber): void
    {
        $this->hallRealtime->notifyRiskSoldOut(
            (int) $draw->id,
            (string) $draw->draw_no,
            strtoupper(trim($normalizedNumber)),
        );
    }

    private function resolveDrawNo(int $drawId): string
    {
        if (isset($this->drawNoById[$drawId])) {
            return $this->drawNoById[$drawId];
        }

        $drawNo = Draw::query()->whereKey($drawId)->value('draw_no');
        $resolved = is_string($drawNo) && $drawNo !== '' ? $drawNo : (string) $drawId;
        $this->drawNoById[$drawId] = $resolved;

        return $resolved;
    }
}
