<?php

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

use App\Models\AdminUser;
use App\Support\ApiResponse;
use App\Models\TransferOrder;
use App\Support\PaginationTrait;
use Illuminate\Http\JsonResponse;
use App\Support\AdminScopePolicy;
use App\Support\AgentNodeApiPresenter;
use App\Support\AdminTransferOrderCapabilities;
use App\Support\CurrencyFormatter;
use App\Services\Wallet\LotteryTransferService;
use App\Http\Controllers\Controller;
use App\Http\Requests\Admin\TransferOrderListRequest;

/**
 * 后台：转账单列表（主站 ↔ 彩票 {@see transfer_orders}）。
 * 检索口径对齐《01-界面文档》§5.11「钱包流水与对账」转账侧扩展。
 *
 * Query：
 * - `page`（默认 1）
 * - `per_page` 或 `size`（每页条数，默认 10，最大 100）
 * - `player_id`（可选，按玩家主键）
 * - `player_account`（可选，模糊匹配 `players.site_player_id` / `username`；与 `player_id` 同时传时以 `player_id` 为准）
 * - `transfer_no`（可选，模糊匹配本地单号）
 * - `external_ref_no`（可选，模糊匹配主站流水号）
 * - `created_from` / `created_to`（可选，`Y-m-d`，筛选创建时间）
 * - `status`（可选，逗号分隔：`processing`,`success`,`failed`,`pending_reconcile`,`reversed`,`manually_processed`）
 * - `abnormal=1`（仅看异常：processing / failed / pending_reconcile，与 `status` 同时出现时优先）
 */
final class TransferOrderListController extends Controller
{
    use PaginationTrait;

    private const ALLOWED_STATUS = ['processing', 'success', 'failed', 'pending_reconcile', 'reversed', 'manually_processed'];

    public function __construct(
        private readonly LotteryTransferService $transferService,
    ) {}

    public function __invoke(TransferOrderListRequest $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);

        $query = TransferOrder::query()
            ->with([
                'player:id,site_code,site_player_id,username,nickname,agent_node_id',
                '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['transfer_no'])) {
            $q = '%'.addcslashes(trim($validated['transfer_no']), '%_\\').'%';
            $query->where('transfer_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 ($request->boolean('abnormal')) {
            $query->whereIn('status', ['processing', 'failed', '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 (TransferOrder $o) => $this->formatRow($o, $admin instanceof AdminUser ? $admin : null),
        );

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

    /**
     * @return array<string, mixed>
     */
    private function formatRow(TransferOrder $o, ?AdminUser $admin): array
    {
        $p = $o->player;
        $amount = (int) $o->amount;

        return [
            'id' => $o->id,
            'transfer_no' => $o->transfer_no,
            ...AgentNodeApiPresenter::embed($p?->agentNode),
            'player_id' => $o->player_id,
            'site_code' => $p?->site_code,
            'site_player_id' => $p?->site_player_id,
            'username' => $p?->username,
            'nickname' => $p?->nickname,
            'direction' => $o->direction,
            'currency_code' => $o->currency_code,
            'amount' => $amount,
            'amount_formatted' => CurrencyFormatter::fromMinor($amount),
            'idempotent_key' => $o->idempotent_key,
            'status' => $o->status,
            ...AdminTransferOrderCapabilities::forOrder($o, $admin, $this->transferService),
            'external_ref_no' => $o->external_ref_no,
            'external_request_payload' => $o->external_request_payload,
            'external_response_payload' => $o->external_response_payload,
            'fail_reason' => $o->fail_reason,
            'created_at' => $o->created_at?->toIso8601String(),
            'finished_at' => $o->finished_at?->toIso8601String(),
        ];
    }
}
