<?php

namespace App\Http\Controllers\Api\V1\Client\Profile;

use App\Enums\NotifyEventType;
use App\Events\NotificationEvent;
use App\Exceptions\CustomWebException;
use App\Http\Controllers\Controller;
use App\Http\Requests\Api\WithdrawRequest;
use App\Models\Admin;
use App\Models\Withdraw;
use App\Models\WithdrawMethod;
use App\Services\Coin\CoinService;
use App\Services\Helper\UniqueCodeGenerator;
use App\Services\ModalIndexQuey;
use App\Traits\Formatter;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Cache;
use Illuminate\Support\Facades\DB;

class WithdrawController extends Controller
{
    use Formatter;

    /**
     * @OA\Get(
     *     path="/api/v1/profile/withdrawals",
     *     summary="Get withdrawals list",
     *     description="Get withdrawals list by user",
     *     tags={"Profile/Deposit"},
     *
     *     @OA\Response(
     *         response=200,
     *         description="Withdrawals list fetched successfully",
     *
     *         @OA\JsonContent(
     *             type="object",
     *
     *             @OA\Property(property="statusCode", type="number", example=200),
     *             @OA\Property(property="data", type="array",
     *
     *                 @OA\Items(
     *                     type="object",
     *
     *                     @OA\Property(property="code", type="string"),
     *                     @OA\Property(property="symbol_position", type="string"),
     *                     @OA\Property(property="symbol", type="string"),
     *                     @OA\Property(property="rate", type="number")
     *                 )
     *             )
     *         )
     *     )
     * )
     */
    public function index(Request $request)
    {
        /**
         * @var \App\Models\User $user
         * */
        $user = $request->user('client');

        $withdrawals = ModalIndexQuey::get(
            $user->withdrawals()->when(request()->status, fn ($q, $status) => $q->where('status', $status)),
            'withdrawMethod:id,name',
        );

        return $this->withSuccess($withdrawals);
    }

    /**
     * @OA\Post(
     *     path="/api/v1/profile/withdraws",
     *     summary="Send withdraw request",
     *     description="Submit contest answer",
     *     tags={"Contests"},
     *
     *     @OA\RequestBody(
     *         required=true,
     *
     *         @OA\JsonContent(
     *             required={"answers", "time_taken"},
     *
     *             @OA\Property(
     *                 property="answers",
     *                 type="string",
     *                 description="The answers submitted by the user."
     *             ),
     *             @OA\Property(
     *                 property="time_taken",
     *                 type="string",
     *                 description="The time taken by the user to complete the contest."
     *             )
     *         )
     *     ),
     *
     *     @OA\Response(
     *         response=200,
     *          description="Success",
     *
     *         @OA\JsonContent(
     *
     *             @OA\Property(property="statusCode", type="number", example=200),
     *             @OA\Property(property="is_correct", type="boolean", example=true),
     *             @OA\Property(property="correct_answers", type="string", example="")
     *         )
     *     ),
     *
     *     @OA\Response(
     *         response=404,
     *         description="User not found.",
     *
     *         @OA\JsonContent(
     *
     *             @OA\Property(property="statusCode", type="number", example=404),
     *             @OA\Property(property="message", type="string", example="User not found")
     *         )
     *     ),
     *
     *     @OA\Response(
     *         response=422,
     *         description="Validation error.",
     *
     *         @OA\JsonContent(
     *
     *             @OA\Property(property="statusCode", type="number", example=422),
     *             @OA\Property(
     *                 property="errors",
     *                 type="object",
     *                 additionalProperties={
     *                     @OA\Property(type="array", @OA\Items(type="string"))
     *                 },
     *             )
     *         )
     *     ),
     *
     *     @OA\Response(
     *         response=401,
     *         description="Invalid OTP.",
     *
     *         @OA\JsonContent(
     *
     *             @OA\Property(property="statusCode", type="number", example=401),
     *             @OA\Property(property="message", type="string", example="Invalid OTP")
     *         )
     *     )
     * )
     */
    public function store(WithdrawRequest $request)
    {
        /**
         * $var \App\Models\User $user
         */
        $user = $request->user('client');

        try {
            DB::beginTransaction();

            if ($user->coins < $request->coins) {
                throw new CustomWebException(__('You don\'t have enough coins'));
            }

            $amount = CoinService::getUSDFromCoins($request->coins);

            $withdraw_method = WithdrawMethod::find($request->withdraw_method_id);

            if (! $withdraw_method->isValidPaymentAmount($amount)) {
                throw new CustomWebException(__('The amount must be between :min and :max', [
                    'min' => $withdraw_method->min,
                    'max' => $withdraw_method->max,
                ]));
            }

            if (! $withdraw_method || $withdraw_method->status != 'active') {
                throw new CustomWebException(__('Withdraw method is not active'));
            }

            if ($withdraw_method->min > $amount || $withdraw_method->max < $amount) {
                throw new CustomWebException(__('The amount must be between :min and :max', [
                    'min' => $withdraw_method->min,
                    'max' => $withdraw_method->max,
                ]));
            }

            $charge = $withdraw_method->totalCharge($amount);

            $withdraw = $user->withdraws()->create([
                'withdraw_method_id' => $withdraw_method->id,
                'track' => UniqueCodeGenerator::make(Withdraw::class, 'track', 6, 'WD'),
                'amount' => $amount,
                'currency' => $withdraw_method->currency,
                'coins' => $request->coins,
                'charge' => $charge,
                'fields' => $request->fields ?? [],
                'status' => 'pending',
            ]);

            event(new NotificationEvent(
                Admin::first(),
                NotifyEventType::WITHDRAW,
                'Withdraw Request',
                'Withdraw requested #'.$withdraw->track
            ));

            DB::commit();

        } catch (\Throwable $th) {

            DB::rollBack();

            return $this->withError($th->getMessage());
        }

        return $this->withSuccess(__('Withdraw request sent successfully'));
    }

    /**
     * @OA\Get(
     *     path="/api/v1/profile/withdraw-methods",
     *     summary="Get withdraw-method list",
     *     description="Get withdraw method list by user",
     *     tags={"Profile/withdrawals"},
     *
     *     @OA\Response(
     *         response=200,
     *         description="withdraws list fetched successfully",
     *
     *         @OA\JsonContent(
     *             type="object",
     *
     *             @OA\Property(property="statusCode", type="number", example=200),
     *             @OA\Property(property="data", type="array",
     *
     *                 @OA\Items(
     *                     type="object",
     *
     *                     @OA\Property(property="code", type="string"),
     *                     @OA\Property(property="symbol_position", type="string"),
     *                     @OA\Property(property="symbol", type="string"),
     *                     @OA\Property(property="rate", type="number")
     *                 )
     *             )
     *         )
     *     )
     * )
     */
    public function getWithdrawMethods()
    {
        $withdraw_methods = Cache::rememberForever('withdraw_method_list', function () {
            return WithdrawMethod::active()->get();
        });

        return $this->withSuccess($withdraw_methods);
    }
}
