<?php

namespace App\Http\Controllers\Api\V1\Wallet;

use App\Models\Player;
use App\Lottery\ErrorCode;
use App\Models\PlayerWallet;
use App\Support\ApiMessage;
use App\Support\ApiResponse;
use App\Support\PlayerFundingMode;
use Illuminate\Support\Facades\DB;
use Illuminate\Http\Request;
use App\Support\CurrencyResolver;
use Illuminate\Http\JsonResponse;
use App\Support\CreditAmountScale;
use App\Support\CurrencyFormatter;
use App\Http\Controllers\Controller;
use App\Services\Wallet\HttpMainSiteWalletBalanceClient;

/**
 * 【玩家】查询彩票侧钱包余额。
 *
 * 路由：`GET /api/v1/wallet/balance`，需 middleware `lottery.player`。
 * PRD：`01-产品文档.md` §10.1.1；金额单位为最小货币 bigint（参见 `docs/04` §8）。
 *
 * 【行为要点】
 * - 币种：优先 Query `currency`，否则使用玩家 `default_currency`，再回退 `config('lottery.default_currency')`
 * - 若尚无 `player_wallets` 记录：按 `wallet_type=lottery` + 币种 **首次开立**一行（余额 0），便于新玩家直接进入查询
 * - `available_balance`：`balance - frozen_balance`，表示当前可用于下注的整数最小货币单位（不为负）
 * - `main_balance`：已配置 `MAIN_SITE_WALLET_API_URL` 时向主站查询；否则 `null`
 */
final class WalletBalanceController extends Controller
{
    private const WALLET_TYPE_LOTTERY = 'lottery';

    public function __construct(
        private readonly HttpMainSiteWalletBalanceClient $mainSiteBalanceClient,
    ) {}

    public function __invoke(Request $request): JsonResponse
    {
        $player = $request->lotteryPlayer();
        abort_if($player === null, 500, 'lottery_player missing');

        $currencyCode = $this->resolveCurrencyCode($request, $player);
        if ($currencyCode instanceof JsonResponse) {
            return $currencyCode;
        }

        if (PlayerFundingMode::usesCredit($player)) {
            $credit = DB::table('player_credit_accounts')->where('player_id', $player->id)->first();
            $limitMajor = (int) ($credit->credit_limit ?? 0);
            $usedMajor = (int) ($credit->used_credit ?? 0);
            $frozenMajor = (int) ($credit->frozen_credit ?? 0);
            $availableMajor = max(0, $limitMajor - $usedMajor - $frozenMajor);

            $limitMinor = CreditAmountScale::majorToMinor($limitMajor, $currencyCode);
            $usedMinor = CreditAmountScale::majorToMinor($usedMajor, $currencyCode);
            $frozenMinor = CreditAmountScale::majorToMinor($frozenMajor, $currencyCode);
            $availableMinor = CreditAmountScale::majorToMinor($availableMajor, $currencyCode);

            return ApiResponse::success([
                'balance' => $limitMinor,
                'balance_formatted' => CurrencyFormatter::fromMinor($limitMinor),
                'available_balance' => $availableMinor,
                'available_balance_formatted' => CurrencyFormatter::fromMinor($availableMinor),
                'credit_limit' => $limitMinor,
                'used_credit' => $usedMinor,
                'credit_line_mode' => true,
                'funding_mode' => PlayerFundingMode::CREDIT,
                'auth_source' => $player->auth_source,
                'main_balance' => null,
                'main_balance_formatted' => null,
                'currency_code' => $currencyCode,
                'wallet_type' => self::WALLET_TYPE_LOTTERY,
                'frozen_balance' => $frozenMinor,
                'frozen_balance_formatted' => CurrencyFormatter::fromMinor($frozenMinor),
            ]);
        }

        $wallet = PlayerWallet::query()->firstOrCreate(
            [
                'player_id' => $player->id,
                'wallet_type' => self::WALLET_TYPE_LOTTERY,
                'currency_code' => $currencyCode,
            ],
            [
                'balance' => 0,
                'frozen_balance' => 0,
                'status' => 0,
                'version' => 0,
            ],
        );

        $balance = (int) $wallet->balance;
        $frozen = (int) $wallet->frozen_balance;
        $available = max(0, $balance - $frozen);

        $mainBalance = $this->mainSiteBalanceClient->fetch($player, $currencyCode);

        return ApiResponse::success([
            'balance' => $balance,
            'balance_formatted' => CurrencyFormatter::fromMinor($balance),
            'available_balance' => $available,
            'available_balance_formatted' => CurrencyFormatter::fromMinor($available),
            'credit_line_mode' => false,
            'funding_mode' => PlayerFundingMode::WALLET,
            'auth_source' => $player->auth_source,
            'main_balance' => $mainBalance,
            'main_balance_formatted' => $mainBalance !== null
                ? CurrencyFormatter::fromMinor($mainBalance)
                : null,
            'currency_code' => $wallet->currency_code,
            'wallet_type' => $wallet->wallet_type,
            'frozen_balance' => $frozen,
            'frozen_balance_formatted' => CurrencyFormatter::fromMinor($frozen),
        ]);
    }

    /**
     * @return string|JsonResponse 合法币种码或错误响应（{@see ErrorCode::WalletInvalidCurrency}）
     */
    private function resolveCurrencyCode(Request $request, Player $player): string|JsonResponse
    {
        $code = CurrencyResolver::resolve($request, $player, 'currency');

        if (! CurrencyResolver::isEnabled($code)) {
            return ApiResponse::error(
                ApiMessage::get($request, 'wallet.invalid_currency'),
                ErrorCode::WalletInvalidCurrency->value,
                null,
                400,
            );
        }

        return $code;
    }
}
