<?php

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

use App\Models\Player;
use App\Models\AgentNode;
use App\Support\ApiResponse;
use App\Support\AdminSiteScope;
use Illuminate\Http\JsonResponse;
use App\Support\PlayerFundingMode;
use Illuminate\Support\Facades\DB;
use App\Support\PlayerApiPresenter;
use App\Http\Controllers\Controller;
use App\Services\Agent\AgentProfileService;
use App\Services\Agent\RebateLimitValidator;
use App\Services\Player\PlayerCreditService;
use Illuminate\Validation\ValidationException;
use App\Services\Player\PlayerRebateProfileService;
use App\Http\Requests\Admin\AdminPlayerUpdateRequest;

/** PUT /api/v1/admin/players/{player} */
final class AdminPlayerUpdateController extends Controller
{
    public function __invoke(
        AdminPlayerUpdateRequest $request,
        Player $player,
        AgentProfileService $agentProfileService,
        PlayerCreditService $playerCreditService,
        RebateLimitValidator $rebateLimitValidator,
        PlayerRebateProfileService $rebateProfileService,
    ): JsonResponse {
        $admin = $request->lotteryAdmin();
        abort_if($admin === null, 401);

        if ($denied = AdminSiteScope::denyUnlessPlayerAccessible($admin, $player)) {
            return $denied;
        }

        $data = $request->validated();

        if (isset($data['status'])) {
            $data['status'] = (int) $data['status'];
        }

        $agent = $player->agent_node_id !== null
            ? AgentNode::query()->find((int) $player->agent_node_id)
            : null;

        if (
            ($request->has('credit_limit') || $request->has('rebate_rate') || $request->has('extra_rebate_rate'))
            && ! PlayerFundingMode::usesCredit($player)
        ) {
            throw ValidationException::withMessages([
                'credit_limit' => ['wallet_player_prohibited'],
            ]);
        }

        $rebateRate = null;
        $extraRebateRate = null;
        if ($agent !== null && ($request->has('rebate_rate') || $request->has('extra_rebate_rate'))) {
            $existing = DB::table('player_rebate_profiles')
                ->where('player_id', $player->id)
                ->where('game_type', '*')
                ->first();

            $rebateRate = $request->has('rebate_rate')
                ? (float) $request->input('rebate_rate', 0) / 100
                : (float) ($existing->rebate_rate ?? 0);
            $extraRebateRate = $request->has('extra_rebate_rate')
                ? (float) $request->input('extra_rebate_rate', 0) / 100
                : (float) ($existing->extra_rebate_rate ?? 0);

            $rebateLimitValidator->assertPlayerRebateWithinAgent(
                $agent,
                $rebateRate,
                $extraRebateRate,
            );
        }

        if ($request->has('credit_limit') && $agent !== null) {
            $newLimit = (int) $request->input('credit_limit', 0);
            $creditRow = DB::table('player_credit_accounts')->where('player_id', $player->id)->first();
            $previous = (int) ($creditRow->credit_limit ?? 0);
            $usedCredit = (int) ($creditRow->used_credit ?? 0) + (int) ($creditRow->frozen_credit ?? 0);
            $agentProfileService->adjustPlayerCreditAllocation($agent, $previous, $newLimit, $usedCredit);
            $playerCreditService->upsertAccount($player, ['credit_limit' => $newLimit]);
            $agentProfileService->refreshAllocatedCredit($agent);
            unset($data['credit_limit']);
        }

        if ($rebateRate !== null || $extraRebateRate !== null) {
            DB::table('player_rebate_profiles')->updateOrInsert(
                ['player_id' => $player->id, 'game_type' => '*'],
                [
                    'inherit_from_agent' => false,
                    'rebate_rate' => $rebateRate ?? 0,
                    'extra_rebate_rate' => $extraRebateRate ?? 0,
                    'updated_at' => now(),
                    'created_at' => now(),
                ],
            );
            unset($data['rebate_rate'], $data['extra_rebate_rate']);
        }

        if ($request->has('rebate_profiles') && $agent !== null) {
            $rebateProfileService->syncProfiles($player->id, $agent, $request->input('rebate_profiles', []));
            unset($data['rebate_profiles']);
        }

        if ($request->has('risk_tags')) {
            $player->risk_tags = array_values(array_unique(array_filter(
                array_map('strval', $request->input('risk_tags', [])),
            )));
            unset($data['risk_tags']);
        }

        unset($data['rebate_profiles']);
        $player->fill(array_filter($data, static fn ($v) => $v !== '' && ! is_array($v)));
        $player->save();

        return ApiResponse::success(PlayerApiPresenter::listItem($player));
    }
}
