<?php

namespace App\Services\Quiz;

use App\Enums\CoinMatterEnum;
use App\Enums\DepositStatusEnum;
use App\Enums\NotificationType;
use App\Enums\NotifyEventType;
use App\Enums\TransactionMatterEnum;
use App\Enums\TransactionStatusEnum;
use App\Events\CoinLogEvent;
use App\Events\InvoiceGenerateEvent;
use App\Events\NotificationEvent;
use App\Models\Admin;
use App\Models\Deposit;
use App\Models\Payment;
use App\Models\Transaction;
use App\Models\User;
use App\Notifications\UserAutoNotification;
use App\Services\Coin\CoinService;

class QuizDepositPayment
{
    public function depositConfirmed(Deposit $deposit)
    {
        $deposit->update([
            'status' => DepositStatusEnum::CONFIRMED,
        ]);

        $this->makeTransaction(
            $deposit->payment,
            [
                'title' => 'Deposit Confirmed',
                'type' => 'credit',
                'charge' => $deposit->charge ?? 0,
                'amount' => $deposit->amount,
                'matter' => TransactionMatterEnum::DEPOSIT,
                'note' => 'Yacht Deposit payment confirmed',
                'status' => TransactionStatusEnum::PAID,
            ]
        );

        $this->updateUserBalance($deposit);

        event(new InvoiceGenerateEvent($deposit));

        $this->notifyUser($deposit->user, NotificationType::DEPOSIT_CONFIRMED, NotifyEventType::DEPOSIT, [
            'amount' => $deposit->amount,
            'deposit_no' => $deposit->deposit_no,
        ]);
    }

    public function depositCancelled(Deposit $deposit)
    {
        $deposit->update([
            'status' => DepositStatusEnum::CANCELLED,
        ]);

        $this->makeTransaction(
            $deposit->payment,
            [
                'title' => 'Deposit Cancelled',
                'type' => 'debit',
                'charge' => $deposit->charge ?? 0,
                'amount' => $deposit->amount,
                'matter' => TransactionMatterEnum::DEPOSIT,
                'note' => 'Yacht Deposit payment cancelled',
                'status' => TransactionStatusEnum::CANCELLED,
            ]
        );

        event(new InvoiceGenerateEvent($deposit));

        $this->notifyUser(
            $deposit->user,
            NotificationType::DEPOSIT_CONFIRMED,
            NotifyEventType::DEPOSIT,
            [
                'amount' => $deposit->amount,
                'track' => $deposit->payment->payment_identifier,
            ]);
    }

    public function depositFailed(Deposit $deposit)
    {
        $deposit->update([
            'status' => DepositStatusEnum::FAILED,
        ]);

        $this->makeTransaction(
            $deposit->payment,
            [
                'title' => 'Deposit Failed',
                'type' => 'debit',
                'charge' => $deposit->charge ?? 0,
                'amount' => $deposit->amount,
                'matter' => TransactionMatterEnum::DEPOSIT,
                'note' => 'Yacht Deposit payment failed',
                'status' => TransactionStatusEnum::FAILED,
            ]
        );

        event(new InvoiceGenerateEvent($deposit));

        $this->notifyUser(
            $deposit->user,
            NotificationType::DEPOSIT_FAILED,
            NotifyEventType::DEPOSIT,
            [
                'amount' => $deposit->amount,
                'track' => $deposit->payment->payment_identifier,
            ]);
    }

    private function makeTransaction(Payment $payment, array $transactionData)
    {
        Transaction::create([
            'holder_id' => $payment->user_id,
            'holder_type' => get_class($payment->user),
            'ref_type' => get_class($payment),
            'ref_id' => $payment->id,
            'track' => $payment->payment_identifier,
            ...$transactionData,
        ]);
    }

    /**
     * Send a notification to a user and an admin for a given yacht event
     *
     * @param  bool  $is_initialized
     * @return void
     */
    public function notifyUser(User $user, NotificationType $notification_type, NotifyEventType $type, array $variables = [])
    {
        $amount = amountWithSymbol($variables['amount']);
        $user->notifyNow(new UserAutoNotification($notification_type, [...$variables, 'amount' => $amount]));

        event(new NotificationEvent(
            Admin::first(),
            $type,
            $notification_type->label(),
            $notification_type->label().' by '.$user->full_name.' for '.$amount,
        ));
    }

    /**
     * Updates the wallet of vendor and admin based on the deposit or deposit status change
     *
     * @return void
     */
    private function updateUserBalance(Deposit $deposit)
    {
        $amount = $deposit->amount;

        $coin = CoinService::calculateCoinsFromUSD($amount);

        $deposit->user->increment('coins', $coin);
        event(new CoinLogEvent($deposit->user, CoinMatterEnum::BALANCE_ADD, $coin, '+'));
    }
}
