<?php

namespace apexl\Io\modules\payment\services;

use apexl\Io\includes\Hook;
use apexl\Io\includes\System;
use apexl\Io\modules\invoice\entities\invoiceEntity;
use apexl\Io\modules\invoice\services\invoiceService;
use apexl\Io\modules\payment\entities\paymentEntity;
use apexl\Io\modules\payment\entities\paymentWebhookLogEntity;
use apexl\Io\modules\payment\providers\stripeProvider;
use apexl\Io\modules\product\entities\productEntity;
use apexl\Io\modules\subscription\entities\subscriptionCreditEntity;
use apexl\Io\modules\subscription\entities\subscriptionEntity;
use apexl\Io\modules\user\entities\userEntity;
use Psr\Http\Message\ResponseInterface as Response;
use Psr\Http\Message\ServerRequestInterface as Request;

class webhookService {

    protected $provider;
    protected $providerName;
    protected $cardValidationService;
    protected $paymentService;

    public function __construct()
    {
        $this->provider = new stripeProvider();
        $this->providerName = 'stripe';
        $this->cardValidationService = new cardValidationService();
        $this->paymentService = new paymentService();
        $this->invoiceService = new invoiceService();
    }

    public function processRequest()
    {

        $payload = @file_get_contents('php://input');

        // Webhook logging
        $log = new paymentWebhookLogEntity();
        $log->received = date('Y-m-d H:i:s');
        $log->method = $_SERVER['REQUEST_METHOD'];
        $log->payload = $payload;
        $log->provider = $this->providerName;
        $log->store();

        $logId = $log->id;

        list($event, $validated, $providerRef, $error, $metadata, $failureMessage, $isFraudulent, $riskLevel, $chargeId) = $this->provider->processWebhookRequest($payload); // Process the webhook request

        // Webhook logging
        $log = new paymentWebhookLogEntity(); // Needed to reload as some weird things happening with the DB
        $log->load($logId);
        $log->event = $event;
        $log->validated = $validated;
        $log->provider_ref = $providerRef;
        $log->error = $error;
        $log->log_data = json_encode($metadata);
        $log->store();

        if ($error) return $error;

        switch ($event) {
            case 'payment_succeeded':
                // Get payment by payment intent id
                $paymentEntity = new paymentEntity();
                $paymentEntity->loadByProviderRef($providerRef);
                if ($paymentEntity->status != "successful") {
                    $paymentEntity->status = 'successful';
                    $paymentEntity->store();
                    $this->cardValidationService->processPaymentResult($paymentEntity);
                    $invoiceEntity = new invoiceEntity();
                    $invoiceEntity->loadByPaymentId($paymentEntity->id);
                    if (isset($invoiceEntity->id) && $invoiceEntity->id > 0) {
                        $this->invoiceService->reenableInvoiceSubscriptions($invoiceEntity);
                        $this->invoiceService->checkAndMarkAsPaid($invoiceEntity);
                        if ($invoiceEntity->send_to_provider == 0 || trim($paymentEntity->remote_order_id) != "") {
                            $invoiceEntity->send_to_provider = 1;
                            $invoiceEntity->store();
                            $this->invoiceService->sendInvoiceToProvider($invoiceEntity->id);
                        } else {
                        $this->invoiceService->submitPaymentToProvider($paymentEntity);
                        }
                    } else {
                        Hook::processHook('payment_completed_without_invoice', $paymentEntity);
                    }
                }
                if ($chargeId && isset($paymentEntity->id) && trim($paymentEntity->provider_ref_2) == '') {
                    $paymentEntity->provider_ref_2 = $chargeId;
                    $paymentEntity->store();
                }

                // Update credit - CREDIT NOW REMOVED ON INVOICING
                //if (isset($metadata->credit_applied)) {
                //    $this->invoiceService->subtractCredit($metadata->dashboard_user_id, $metadata->credit_applied, "used credit for subscription payment");
                //}
                break;
            case 'payment_failed':
                // Get payment by payment intent id
                $paymentEntity = new paymentEntity();
                $paymentEntity->loadByProviderRef($providerRef);
                if ($paymentEntity->status != "failed") {
                    $paymentEntity->status = 'failed';
                    $paymentEntity->store();
                    $this->cardValidationService->processPaymentResult($paymentEntity);
                    $invoiceEntity = new invoiceEntity();
                    $invoiceEntity->loadByPaymentId($paymentEntity->id);
                    $this->invoiceService->checkStoreFailedAttempts($invoiceEntity, $paymentEntity);
                }
                break;
        }

        // Store error / fraud details
        if (isset($paymentEntity) && isset($paymentEntity->id) && $paymentEntity->id > 0) {
            if ($failureMessage) $paymentEntity->failure_reason = $failureMessage;
            if ($riskLevel) $paymentEntity->risk_level = $riskLevel;
            if ($isFraudulent) {
                $paymentEntity->fraudulent = 1;
                if ($paymentEntity->user_id > 0) {
                    $userEntity = new userEntity();
                    $userEntity->load($paymentEntity->user_id, true);
                    if (isset($userEntity->id) && $userEntity->id > 0) {
                        $userEntity->marked_fraudulent = 1;
                        $userEntity->active = 0;
                        $userEntity->store();
                    }
                }
            }
            if ($failureMessage || $isFraudulent || $riskLevel) $paymentEntity->store();
        }



    }


}