<?php

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

use App\Models\Player;
use App\Models\WalletTxn;
use App\Support\ApiResponse;
use App\Support\PaginationTrait;
use Illuminate\Http\JsonResponse;
use App\Support\AdminScopePolicy;
use App\Support\AgentNodeApiPresenter;
use App\Support\CurrencyFormatter;
use App\Support\PlayerFundingMode;
use App\Http\Controllers\Controller;
use App\Http\Requests\Admin\WalletTransactionListRequest;
use App\Services\Wallet\PlayerLedgerLogsService;

/**
 * 后台：彩票钱包流水列表 {@see wallet_txns}。
 * 列表字段对齐《01-界面文档》§5.11；`updated_at` 作「完成时间」展示（`created_at` 为请求时间）。
 *
 * Query：
 * - `page`、`per_page` / `size`
 * - `player_id`（可选）
 * - `player_account`（可选，模糊匹配 `site_player_id` / `username`；与 `player_id` 同时传时以 `player_id` 为准）
 * - `txn_no`（可选，模糊匹配流水号）
 * - `external_ref_no`（可选，模糊匹配主站流水号）
 * - `created_from` / `created_to`（可选，`Y-m-d`，按 `created_at`）
 * - `biz_type`（可选）
 * - `status`（可选，逗号：`posted`,`pending_reconcile`）
 * - `abnormal=1`（仅 `pending_reconcile`，优先于 `status`）
 */
final class WalletTransactionListController extends Controller
{
    use PaginationTrait;

    private const ALLOWED_STATUS = ['posted', 'pending_reconcile', 'reversed'];

    public function __construct(
        private readonly PlayerLedgerLogsService $ledgerLogs,
    ) {}

    public function __invoke(WalletTransactionListRequest $request): JsonResponse
    {
        $admin = $request->lotteryAdmin();
        abort_if($admin === null, 401);

        $validated = $request->validated();
        $scope = AdminScopePolicy::resolveContext($request, $admin);

        $perPage = $this->perPage($request, 'per_page', 10, 100);
        $page = $this->page($request);

        if (! empty($validated['player_id'])) {
            $player = Player::query()->find((int) $validated['player_id']);
            if ($player !== null && PlayerFundingMode::usesCredit($player)) {
                $credit = $this->ledgerLogs->listForAdminPlayer(
                    $player,
                    $page,
                    $perPage,
                    isset($validated['biz_type']) ? (string) $validated['biz_type'] : null,
                );

                return ApiResponse::success($credit);
            }
        }

        $query = WalletTxn::query()
            ->with([
                'player:id,site_code,site_player_id,username,nickname,agent_node_id,funding_mode,auth_source',
                'player.agentNode:id,code,name',
            ])
            ->orderByDesc('id');

        if (! empty($validated['player_id'])) {
            $query->where('player_id', (int) $validated['player_id']);
        } elseif (! empty($validated['player_account'])) {
            $term = '%'.addcslashes(trim($validated['player_account']), '%_\\').'%';
            $query->whereHas('player', function ($q) use ($term): void {
                $q->where('site_player_id', 'like', $term)
                    ->orWhere('username', 'like', $term);
            });
        }

        if (! empty($validated['txn_no'])) {
            $q = '%'.addcslashes(trim($validated['txn_no']), '%_\\').'%';
            $query->where('txn_no', 'like', $q);
        }

        if (! empty($validated['external_ref_no'])) {
            $q = '%'.addcslashes(trim($validated['external_ref_no']), '%_\\').'%';
            $query->where('external_ref_no', 'like', $q);
        }

        if (! empty($validated['created_from'])) {
            $query->where('created_at', '>=', $validated['created_from'].' 00:00:00');
        }

        if (! empty($validated['created_to'])) {
            $query->where('created_at', '<=', $validated['created_to'].' 23:59:59');
        }

        if (! empty($validated['biz_type'])) {
            $query->where('biz_type', trim((string) $validated['biz_type']));
        }

        if ($request->boolean('abnormal')) {
            $query->where('status', 'pending_reconcile');
        } elseif (! empty($validated['status'])) {
            $parts = array_filter(array_map('trim', explode(',', (string) $validated['status'])));
            $statuses = array_values(array_intersect($parts, self::ALLOWED_STATUS));
            if ($statuses !== []) {
                $query->whereIn('status', $statuses);
            }
        }

        AdminScopePolicy::applyViaPlayerRelationWithContext($query, $scope, 'player');

        $paginator = $query->paginate($perPage, ['*'], 'page', $page);
        $items = $paginator->getCollection()->map(fn (WalletTxn $t) => $this->formatRow($t));

        return ApiResponse::success([
            'items' => $items,
            'total' => $paginator->total(),
            'page' => $paginator->currentPage(),
            'per_page' => $paginator->perPage(),
        ]);
    }

    /**
     * @return array<string, mixed>
     */
    private function formatRow(WalletTxn $t): array
    {
        $p = $t->player;
        $amount = (int) $t->amount;
        $balanceBefore = (int) $t->balance_before;
        $balanceAfter = (int) $t->balance_after;

        return [
            'id' => $t->id,
            'txn_no' => $t->txn_no,
            ...AgentNodeApiPresenter::embed($p?->agentNode),
            'player_id' => $t->player_id,
            'site_code' => $p?->site_code,
            'site_player_id' => $p?->site_player_id,
            'username' => $p?->username,
            'nickname' => $p?->nickname,
            'wallet_id' => $t->wallet_id,
            'biz_type' => $t->biz_type,
            'biz_no' => $t->biz_no,
            'direction' => (int) $t->direction,
            'amount' => $amount,
            'amount_formatted' => CurrencyFormatter::fromMinor($amount),
            'balance_before' => $balanceBefore,
            'balance_before_formatted' => CurrencyFormatter::fromMinor($balanceBefore),
            'balance_after' => $balanceAfter,
            'balance_after_formatted' => CurrencyFormatter::fromMinor($balanceAfter),
            'status' => $t->status,
            'external_ref_no' => $t->external_ref_no,
            'idempotent_key' => $t->idempotent_key,
            'remark' => $t->remark,
            'created_at' => $t->created_at?->toIso8601String(),
            'updated_at' => $t->updated_at?->toIso8601String(),
            'ledger_source' => 'wallet_txn',
            'funding_mode' => $p?->funding_mode,
            'auth_source' => $p?->auth_source,
        ];
    }
}
