<?php

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

use App\Models\Draw;
use App\Models\RiskPool;
use App\Lottery\ErrorCode;
use App\Support\ApiMessage;
use App\Support\ApiResponse;
use Illuminate\Http\Request;
use App\Models\RiskPoolLockLog;
use Illuminate\Http\JsonResponse;
use Illuminate\Support\Facades\DB;
use App\Http\Controllers\Controller;
use App\Services\Ticket\RiskPoolService;

final class AdminRiskPoolManualStatusController extends Controller
{
    public function __construct(
        private readonly RiskPoolService $riskPoolService,
    ) {}
    public function close(Request $request, Draw $draw, string $number_4d): JsonResponse
    {
        $pool = $this->updateStatus($draw, $number_4d, true, 'close', 'admin_manual_close');

        if ($pool === null) {
            return ApiMessage::errorResponse($request, 'not_found', ErrorCode::ClientHttpError->value, null, 404);
        }

        return ApiResponse::success($this->row($pool));
    }

    public function recover(Request $request, Draw $draw, string $number_4d): JsonResponse
    {
        $pool = $this->updateStatus($draw, $number_4d, false, 'recover', 'admin_manual_recover');

        if ($pool === null) {
            return ApiMessage::errorResponse($request, 'not_found', ErrorCode::ClientHttpError->value, null, 404);
        }
        if ((int) $pool->remaining_amount <= 0) {
            return ApiMessage::errorResponse($request, 'risk_pool_no_remaining_amount', ErrorCode::ClientHttpError->value, [
                'reason' => 'risk_pool_no_remaining_amount',
            ], 409);
        }

        return ApiResponse::success($this->row($pool));
    }

    private function updateStatus(
        Draw $draw,
        string $number4d,
        bool $soldOut,
        string $actionType,
        string $reason,
    ): ?RiskPool {
        return DB::transaction(function () use ($draw, $number4d, $soldOut, $actionType, $reason): ?RiskPool {
            $pool = RiskPool::query()
                ->where('draw_id', $draw->id)
                ->where('normalized_number', $number4d)
                ->lockForUpdate()
                ->first();

            if ($pool === null) {
                return null;
            }
            if (! $soldOut && (int) $pool->remaining_amount <= 0) {
                return $pool;
            }

            $targetStatus = $soldOut ? 1 : 0;
            $soldOutBefore = (int) $pool->sold_out_status;
            if ($soldOutBefore !== $targetStatus) {
                $pool->forceFill([
                    'sold_out_status' => $targetStatus,
                    'version' => (int) $pool->version + 1,
                ])->save();

                if ($targetStatus === 1) {
                    $this->riskPoolService->publishManualSoldOut($draw, $number4d);
                }

                RiskPoolLockLog::query()->create([
                    'draw_id' => $draw->id,
                    'normalized_number' => $number4d,
                    'ticket_item_id' => null,
                    'action_type' => $actionType,
                    'amount' => 0,
                    'source_reason' => $reason,
                    'created_at' => now(),
                ]);
            }

            $fresh = $pool->fresh();
            if ($fresh !== null) {
                $this->riskPoolService->syncRedisStateFromPool($fresh);
            }

            return $fresh;
        });
    }

    /** @return array<string, mixed> */
    private function row(RiskPool $pool): array
    {
        $cap = (int) $pool->total_cap_amount;
        $locked = (int) $pool->locked_amount;

        return [
            'normalized_number' => $pool->normalized_number,
            'total_cap_amount' => $cap,
            'locked_amount' => $locked,
            'remaining_amount' => (int) $pool->remaining_amount,
            'sold_out_status' => (int) $pool->sold_out_status,
            'is_sold_out' => (int) $pool->sold_out_status === 1,
            'usage_ratio' => $cap > 0 ? round($locked / $cap, 6) : null,
            'version' => (int) $pool->version,
        ];
    }
}
