<?php

namespace apexl\Io\modules\subscription\controllers;

use apexl\Config\Singleton;
use apexl\Io\includes\Controller;
use apexl\Io\includes\Hook;
use apexl\Io\includes\Routes;
use apexl\Io\includes\System;
use apexl\Io\modules\company\entities\companyEntity;
use apexl\Io\modules\invoice\entities\invoiceEntity;
use apexl\Io\modules\payment\entities\paymentTokenEntity;
use apexl\Io\modules\payment\services\paymentService;
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\subscription\services\subscriptionService;
use apexl\Io\modules\subscriptionDisplay\components\viewTiles;
use apexl\Io\modules\user\entities\userEntity;
use apexl\Io\modules\user\services\currentUser;
use apexl\Io\services\Logger;
use apexl\Io\services\pathUtility;
use app\module\billing\entities\billingSimSettingsEntity;
use app\module\simcard\services\simService;
use Psr\Http\Message\ResponseInterface as Response;
use Psr\Http\Message\ServerRequestInterface as Request;

class subscriptionController extends Controller {

    public function __construct(pathUtility $path, Singleton $config)
    {
        parent::__construct();
        $this->path = $path;
        $this->config = $config;
    }

    public function subscriptionListTableData(Request $request, Response $response){
        $params = $request->getQueryParams();
        $entity = new subscriptionEntity();
        $filters = $this->buildFilterConditions($entity, $params);
        $entityData = $entity->loadSubscriptionListByPage($params, $filters, $params['orderBy'] ?? []);

        $entityData['tableHeader'] = ['ID', 'User', 'Product', 'Qty', '1st Payment', 'Created', 'Next Billing Date', 'Last Billed', 'State', 'SIMs', '1st Transaction Status', 'Order ID', 'Order Status'];

        $rows = [];
        foreach($entityData['data'] as $result){
            $rowSub = new subscriptionEntity();
            $rowSub->load($result->id);
            $subData = $rowSub->getData();
            $orderData = $rowSub->getWordPressOrderStatus($result->remote_order_id);
            $row = [
                'id' => $subData['id'],
                'user' => $subData['user_id'],
                'product' => $subData['product_id'],
                'qty' => $subData['product_quantity'],
                'amount' => '£'.$result->amount,
                'created' => $subData['created'],
                'nbd' => $subData['next_billing_date'],
                'lb' => $subData['last_billing_date'],
                'state' => $subData['enabled'],
                'sims' => $result->assigned_sims,
                'transaction' => $result->status,
                'order' => $result->remote_order_id,
                'order_status' => isset($orderData['status']) ? "<div class='woostatus ".$orderData['status']."'>".$orderData['status'].'</div>' : ''
            ];
            $rows[] = $row;
        }

        $entityData['rows'] = $rows;
        unset($entityData['data']);

        return System::asJson($response, $entityData);
    }

    public function subscriptionListTableDataBasic(Request $request, Response $response){
        $params = $request->getQueryParams();
        $entity = new subscriptionEntity();
        $paymentService = new paymentService();
        $userEntity = new userEntity();

        $currentUser = currentUser::getCurrentUser();

        if (!$currentUser->isAllowed('administer')) {
            //$userEntity->getUserByEmail($currentUser->email); // Customers invoices shown based on access rules in config.json
            //$params['user_id'] = $userEntity->id ?? 0;
        } elseif (isset($params['userEmail'])) {
            $userEntity->getUserByEmail($params['userEmail']);
        $params['user_id'] = $userEntity->id ?? 0;
        }

        if (isset($params['id'])) {
            $params['subscription.id'] = $params['id'];
            unset($params['id']);
        }

        $filters = $this->buildFilterConditions($entity, $params);

        $subscriptions = $entity->loadMultiple($filters, $params['orderBy'] ?? []); // Note - this includes access control with correct config

        $entityData['tableHeader'] = ['#', 'Created', 'Next Billing Date', 'Bundle', 'Quantity', 'Type', 'Payment Method', 'Amount', 'Status'];

        $rows = [];

        $productEntity = new productEntity();
        $products = $productEntity->getAll();
        $priceCache = [];
        foreach ($products as $product) {
            $priceCache[$product->product_name] = $product->price;
        }
        $paymentTokenEntity = new paymentTokenEntity();
        $billingTokens = [];

        foreach($subscriptions as $subscription){

            $subData = $subscription->getData();

            $paymentMethod = "";
            if ($subscription->payment_provider == 'stripe') {
                if (!isset($billingTokens[$subscription->user_id])) {
                    $billingTokens[$subscription->user_id] = $paymentTokenEntity->getBillingTokenForUser($subscription->user_id, $subscription->payment_provider);
                    if (isset($billingTokens[$subscription->user_id])) {
                    $cardData[$subscription->user_id] = $paymentService->getCardDataForToken($billingTokens[$subscription->user_id]);
                }
                }
                if (isset($billingTokens[$subscription->user_id])) {
                $providerData = $cardData[$subscription->user_id];
                    $paymentMethod = is_object($providerData) ? ucfirst($providerData->funding) . ' Card<br>**** ' . $providerData->last4 . '<br>' . $providerData->exp_month . '/' . $providerData->exp_year : '';
                } else {
                    $paymentMethod = 'None';
                }
            }

            $created = \DateTime::createFromFormat('Y-m-d', $subscription->date_starts);
            $nextBillingDate = \DateTime::createFromFormat('Y-m-d', $subscription->next_billing_date);
            $amount = isset($priceCache[$subData['product_id']]) ? '£'.$priceCache[$subData['product_id']] : 'N/A';
            if (trim($subscription->price_override) != "") $amount = '£'.trim($subscription->price_override);
            $row = [
                'id' => $subscription->id,
                'created' => $created ? $created->format('d M Y') : '',
                'next_billing_date' => $nextBillingDate ? $nextBillingDate->format('d M Y') : '',
                'product' => $subData['product_id'],
                'qty' => $subData['product_quantity'],
                'type' => $subscription->payment_provider,
                'payment_method' => $paymentMethod,
                'amount' => $amount,
                'status' => viewTiles::getSubscriptionStatusText($subscription),
            ];
            $rows[] = $row;
        }

        $entityData['rows'] = $rows;
        $entityData['totalData'] = count($rows);
        unset($entityData['data']);

        $entityData = Hook::processHook('subscriptionListBasicAlter', $entityData);

        return System::asJson($response, $entityData);
    }

    public function subscriptionListTableDataToCancel(Request $request, Response $response){
        $params = $request->getQueryParams();
        $entity = new subscriptionEntity();
        $paymentService = new paymentService();

        $params['enabled'] = 1;
        $filters = $this->buildFilterConditions($entity, $params);

        $subscriptions = $entity->loadMultiple($filters, $params['orderBy'] ?? []); // Note - this includes access control with correct config

        $entityData['tableHeader'] = ['#', 'Created', 'Next Billing Date', 'Bundle', 'Quantity', 'Type', 'Payment Method', 'Amount', 'Status'];

        $rows = [];

        $productEntity = new productEntity();
        $products = $productEntity->getAll();
        $priceCache = [];
        foreach ($products as $product) {
            $priceCache[$product->product_name] = $product->price;
        }
        $paymentTokenEntity = new paymentTokenEntity();
        $billingTokens = [];

        foreach($subscriptions as $subscription){

            $subData = $subscription->getData();

            $paymentMethod = "";
            if ($subscription->payment_provider == 'stripe') {
                if (!isset($billingTokens[$subscription->user_id])) {
                    $billingTokens[$subscription->user_id] = $paymentTokenEntity->getBillingTokenForUser($subscription->user_id, $subscription->payment_provider);
                    if (isset($billingTokens[$subscription->user_id])) {
                        $cardData[$subscription->user_id] = $paymentService->getCardDataForToken($billingTokens[$subscription->user_id]);
                    }
                }
                if (isset($billingTokens[$subscription->user_id])) {
                    $providerData = $cardData[$subscription->user_id];
                    $paymentMethod = is_object($providerData) ? ucfirst($providerData->funding) . ' Card<br>**** ' . $providerData->last4 . '<br>' . $providerData->exp_month . '/' . $providerData->exp_year : '';
                } else {
                    $paymentMethod = 'None';
                }
            }

            $created = \DateTime::createFromFormat('Y-m-d', $subscription->date_starts);
            $nextBillingDate = \DateTime::createFromFormat('Y-m-d', $subscription->next_billing_date);
            $amount = isset($priceCache[$subData['product_id']]) ? '£'.$priceCache[$subData['product_id']] : 'N/A';
            if (trim($subscription->price_override) != "") $amount = '£'.trim($subscription->price_override);
            $row = [
                'id' => $subscription->id,
                'created' => $created ? $created->format('d M Y') : '',
                'next_billing_date' => $nextBillingDate ? $nextBillingDate->format('d M Y') : '',
                'product' => $subData['product_id'],
                'qty' => $subData['product_quantity'],
                'type' => $subscription->payment_provider,
                'payment_method' => $paymentMethod,
                'amount' => $amount,
                'status' => viewTiles::getSubscriptionStatusText($subscription),
            ];
            $rows[] = $row;
        }

        $entityData['rows'] = $rows;
        $entityData['totalData'] = count($rows);
        unset($entityData['data']);

        $entityData = Hook::processHook('subscriptionListBasicAlter', $entityData);

        return System::asJson($response, $entityData);
    }

    public function troubleshootData(Request $request, Response $response){

        $subscriptionEntity = new subscriptionEntity();
        $subscriptions = $subscriptionEntity->fetchAllForTroubleshoot();

        $invoiceEntity = new invoiceEntity();
        $overdueInvoices = $invoiceEntity->getOverdueBySubscription();

        $issues = [];
        $today = date('Y-m-d', strtotime('-1day'));
        $oneMonthAgo = (new \DateTime('now'))->sub(new \DateInterval('P31D'));

        foreach ($subscriptions as $subscription) {

            // Has overdue invoices
            if (isset($overdueInvoices[$subscription->id]) && $subscription->payment_provider == 'stripe') {
                $issues[$subscription->id][] = 'Has unpaid invoices';
            }

            // Billing Overdue - invoice should have been raised
            if ($subscription->enabled == '1' && $subscription->next_billing_date < $today) {
                $issues[$subscription->id][] = "Invoice should have been raised, but hasn't";
            }

            // Subscription pending cancellation
            if ($subscription->enabled == '1' && $subscription->cancellation_date) {
                $issues[$subscription->id][] = 'Subscription pending cancellation';
            }

            // Subscription pending cancellation
            if ($subscription->enabled == '1' && $subscription->last_billing_date && $subscription->last_billing_date < $oneMonthAgo->format('Y-m-d')) {
                $issues[$subscription->id][] = 'Subscription uninvoiced for more than one month';
            }
        }

        $newIssues = Hook::processHook('subscriptionTroubleshootIssuesModify', $subscriptions, $issues);
        if (is_array($newIssues)) $issues = $newIssues;

        $entityData['tableHeader'] = [
            '#',
            'userId',
            'Created',
            'Customer',
            'Next Billing Date',
            'Bundle',
            'Quantity',
            'Type',
            'Amount',
            'Status',
            'Issues',
            'Notes'
        ];

        $rows = [];

        $productEntity = new productEntity();
        $products = $productEntity->getAll();
        $priceCache = [];
        $nameCache = [];
        foreach ($products as $product) {
            $priceCache[$product->id] = $product->price;
            $nameCache[$product->id] = $product->product_name;
        }


        foreach($subscriptions as $subscription){
            if (isset($issues[$subscription->id])) {

                $subIssues = $issues[$subscription->id];
                $subIssues = array_unique($subIssues);

                $created = \DateTime::createFromFormat('Y-m-d', $subscription->date_starts);
                $nextBillingDate = \DateTime::createFromFormat('Y-m-d', $subscription->next_billing_date);
                $amount = isset($priceCache[$subscription->product_id]) ? '£' . $priceCache[$subscription->product_id] : 'N/A';
                if (trim($subscription->price_override) != "") $amount = '£'.trim($subscription->price_override);
                $row = [
                    'id' => $subscription->id,
                    'userId' => $subscription->user_id,
                    'created' => $created->format('d M Y'),
                    'email' => $subscription->email,
                    'next_billing_date' => $nextBillingDate ? $nextBillingDate->format('d M Y') : 'Not Set',
                    'product' => $nameCache[$subscription->product_id] ?? '',
                    'qty' => $subscription->product_quantity,
                    'type' => strtoupper($subscription->payment_provider),
                    'amount' => $amount,
                    'status' => viewTiles::getSubscriptionStatusText($subscription),
                    'issues' => implode("<br>", $subIssues),
                    'notes' => '<span class="fw-bold">'.$subscription->tbshoot_notes.'</span>'
                ];
                $rows[] = $row;
            }
        }

        $entityData['rows'] = $rows;
        $entityData['totalData'] = count($rows);
        unset($entityData['data']);

        $entityData = Hook::processHook('subscriptionListBasicAlter', $entityData);

        return System::asJson($response, $entityData);
    }


    public function updateSubscription(Request $request, Response $response)
    {
        $body = $request->getParsedBody();
        $user = currentUser::getCurrentUser();
        $body->loggedInUserId = $user->id ?? null;
        Logger::log('subscription_update_start', $body);
        if(!isset($body->subscription_id) || !$body->subscription_id){
            Logger::log('subscription_update_id_missing', $body);
            $this->output::addMessage('subscription.update', 'error', 'Subscription ID missing');
            $this->output::addResponse($request, [], FALSE); // added so we can hook into this elsewhere.
            return System::asJson($response, [], 400);
        }

        $subscription = new subscriptionEntity();
        $subscription->load($body->subscription_id);
        if (!$subscription->id) {
            Logger::log('subscription_update_does_not_exist', $body);
            $this->output::addMessage('subscription.update', 'error', 'Subscription does not exist');
            $this->output::addResponse($request, [], FALSE); // added so we can hook into this elsewhere.
            return System::asJson($response, [], 400);
        }

        $responseData = [];
        $previousProductId = $subscription->product_id;
        if (isset($body->product_id) && $body->product_id > 0) $subscription->product_id = $body->product_id;
        if (isset($body->product_quantity) && $body->product_quantity > 0) $subscription->product_quantity = $body->product_quantity;
        if (isset($body->tbshoot_omit)) $subscription->tbshoot_omit = $body->tbshoot_omit ? 1 : 0;
        if (isset($body->tbshoot_notes)) $subscription->tbshoot_notes = $body->tbshoot_notes;
        if (isset($body->product_id) && $body->product_id > 0) $subscription->product_id = $body->product_id;
        if (isset($body->enabled)) {
        if ($body->enabled && !$subscription->enabled) {
            Logger::log('subscription_update_enable', $body);
            Hook::processHook('subscription_enabled', $subscription, 'Subscription manually enabled');
            } elseif (!$body->enabled && $subscription->enabled) {
                Logger::log('subscription_update_disable', $body);
                Hook::processHook('subscription_disabled', $subscription, 'Subscription manually disabled');
            }
            $subscription->enabled = $body->enabled ? TRUE : FALSE;
            if ($subscription->enabled) {
                if (isset($this->config->app->payments->subscriptions->autoDeSuspendOnEnable) && $this->config->app->payments->subscriptions->autoDeSuspendOnEnable) {
                    $subscription->suspended = FALSE;
                }
            }
            if ($body->enabled && $subscription->enabled == '0') {
                $subscription->cancellation_date = NULL;
            } elseif (!$body->enabled && $subscription->enabled == '1') {
                $subscription->suspension_date = date('Y-m-d H:i:s');
                $subscription->cancellation_date = date('Y-m-d');
                $subscription->cancellation_reason = "Disabled by user ".$user->getNiceName();
            }
        }
        $subscription->next_billing_date = $body->next_billing_date;
        $subscription->store();
        Logger::log('subscription_update_complete', $subscription->getData());
        $this->output::addMessage('subscription.update', 'success', 'DB Subscription Successfully updated!');
        $this->output::addMetadata('subscription.update', 'events', [(object)['name' => 'closeModal', 'value' => true]]);

        Hook::processHook('subscription_edit_form_saved', $subscription);

        if ($previousProductId != $subscription->product_id) {
            $messages = Hook::processHook('subscription_product_changed', $subscription, $previousProductId);
            $responseData['refreshGlobal'] = true;
            if (isset($messages) && is_array($messages)) {
                foreach ($messages as $message) {
                    $this->output::addMessage($message->name, $message->type, $message->message);
                }
            }
        }

        return System::asJson($response, $responseData);
    }

    public function createSubscription(Request $request, Response $response)
    {
        $body = $request->getParsedBody();

        $companyEntity = new companyEntity();
        $companyEntity->loadByUser($body->user_id);
        $subscriptionService = new subscriptionService();
        $subscription = $subscriptionService->createSubscription($companyEntity->id ?? 0, $body->user_id, $body->product_id, $body->product_quantity, date('Y-m-d'), $body->grace_period_ends, $body->next_billing_date);

        if (isset($subscription->id) && $subscription->id > 0) {
            Logger::log('subscription_created', $subscription->getData());
            $this->output::addMetadata('subscription.created_1', 'refreshByTag', ['user-subscriptions-table']);
            $this->output::addMetadata('subscription.created_2', 'events', [(object)['name' => 'closeModal', 'value' => true]]);
            $this->output::addMessage('subscription.create', 'success', 'DB Subscription Successfully created');
        } else {
            $this->output::addMessage('subscription.create', 'error', 'Subscription not created');
        }

        return System::asJson($response);
    }

    public function changeSubscription(Request $request, Response $response, $args)
    {
        $subscriptionEntity = new subscriptionEntity();
        $subscriptionEntity->load($args['id']);

        $currentUser = currentUser::getCurrentUser();
        if(!$currentUser->isAllowed('ManageUsers') && !$currentUser->isAllowed('UpdateSubscriptions') && $currentUser->id != $subscriptionEntity->user_id) {
            return System::asJson($response, [], 403);
        }

        $body = $request->getParsedBody();

        if (!$body->acceptTerms) {
            $this->output::addMessage('subscription.change', 'error', 'Please tick to understand you accept the terms and conditions');
            $this->output::addResponse($request, [], FALSE);
            return System::asJson($response);
        } elseif (!isset($body->product_id) || !$body->product_id) {
            $this->output::addMessage('subscription.change', 'error', 'Please choose a new product for your subscription');
            $this->output::addResponse($request, [], FALSE);
            return System::asJson($response);
        } else {
            // charge payment method
            // Note change
            $result = (object)[];
            $result = Hook::processHook('subscription_pre_customer_change_product', $result, $subscriptionEntity, $body->product_id);

            if (isset($result->success) && $result->success) {
                $subscriptionService = new subscriptionService();
                $nextBillingDate = (new \DateTime('now'))->add(new \DateInterval('P1M'));
                $subscriptionService->changeSubscriptionProductNow($subscriptionEntity, $body->product_id, (new \DateTime('now')), $nextBillingDate);

                $this->output::addMessage('subscription.change', 'success', 'Your subscription has been successfully changed.');
               // $this->output::addMetadata('subscription.change-cm', 'events', [(object)['name' => 'closeModal', 'value' => true]]);
                $this->output::addMetadata('subscription.change', 'reloadPage', []);
            } elseif (isset($result->redirectUrl) && $result->redirectUrl) {
                //System::redirect($result->redirectUrl);
                $this->output::addMetadata(
                    'subscription.change',
                    'redirect',
                    $result->redirectUrl
                );
                //$this->output::addMetadata('subscription.change', 'events', [(object)['name' => 'changeModalContentSrc', 'value' => $result->redirectUrl]]);
            } else {
                $this->output::addMessage('subscription.change', 'error', 'The change to your subscription could not be completed.');
            }
        }

        return System::asJson($response, []);
    }

    public function restartSubscription(Request $request, Response $response, $args)
    {
        $subscriptionEntity = new subscriptionEntity();
        $subscriptionEntity->load($args['id']);

        $currentUser = currentUser::getCurrentUser();
        if(!$currentUser->isAllowed('ManageUsers') && !$currentUser->isAllowed('UpdateSubscriptions') && $currentUser->id != $subscriptionEntity->user_id) {
            return System::asJson($response, [], 403);
        }

        $body = $request->getParsedBody();

        if (!$body->acceptTerms) {
            $this->output::addMessage('subscription.restart', 'error', 'Please tick to understand you accept the terms and conditions');
            $this->output::addResponse($request, [], FALSE);
            return System::asJson($response);
        } elseif (!isset($body->product_id) || !$body->product_id) {
            $this->output::addMessage('subscription.restart', 'error', 'Please choose a new product for your subscription');
            $this->output::addResponse($request, [], FALSE);
            return System::asJson($response);
        } else {
            // charge payment method
            // Note change
            $result = (object)[];
            $result = Hook::processHook('subscription_pre_customer_restart_subscription', $result, $subscriptionEntity, $currentUser->id, $body->product_id, $args['meta'] ?? null);

            if (isset($result->success) && $result->success) {
                $subscriptionService = new subscriptionService();
                $nextBillingDate = (new \DateTime('now'))->add(new \DateInterval('P1M'));
                $gracePeriodEnds = clone $nextBillingDate;
                $gracePeriodEnds->sub(new \DateInterval('P1D'));
                $companyEntity = new CompanyEntity();
                $companyEntity->loadByUser($currentUser->id);
                $newSubscriptionEntity = $subscriptionService->createSubscription($companyEntity->id??null, $currentUser->id, $body->product_id, 1, (new \DateTime('now')), $gracePeriodEnds, $nextBillingDate);
                $result = Hook::processHook('subscription_post_customer_restart_subscription', $newSubscriptionEntity, $args['meta']);
                $this->output::addMessage('subscription.restart', 'success', 'Your subscription has been successfully restarted.');
                // $this->output::addMetadata('subscription.change-cm', 'events', [(object)['name' => 'closeModal', 'value' => true]]);
                $this->output::addMetadata('subscription.restart', 'reloadPage', []);
            } elseif (isset($result->redirectUrl) && $result->redirectUrl) {
                //System::redirect($result->redirectUrl);
                $this->output::addMetadata(
                    'subscription.restart',
                    'redirect',
                    $result->redirectUrl
                );
                //$this->output::addMetadata('subscription.change', 'events', [(object)['name' => 'changeModalContentSrc', 'value' => $result->redirectUrl]]);
            } elseif (isset($result->error) && $result->error) {
                $this->output::addMessage('subscription.restart', 'error', $result->error);
            } else {
                $this->output::addMessage('subscription.restart', 'error', 'Your subscription could not be restarted.');
            }
        }

        return System::asJson($response, []);
    }

    public function suspendSubscription(Request $request, Response $response, $args)
    {
        $subscriptionEntity = new subscriptionEntity();
        $subscriptionEntity->load($args['id']);

        $currentUser = currentUser::getCurrentUser();
        if(!$currentUser->isAllowed('ManageUsers') && !$currentUser->isAllowed('UpdateSubscriptions') && $currentUser->id != $subscriptionEntity->user_id) {
            return System::asJson($response, [], 403);
        }

        if (isset($subscriptionEntity) && $subscriptionEntity->id == $args['id']) {
            if (isset($args['cancellationDate']) && preg_match('/^[0-9]{4}\-[0-9]{2}\-[0-9]{2}$/', $args['cancellationDate'])) {
                $subscriptionEntity->cancellation_date = $args['cancellationDate'];
                $subscriptionEntity->cancellation_reason = "Cancelled by ".$currentUser->getNiceName();
                $subscriptionEntity->store();
                $entityData = Hook::processHook('subscription_schedule_cancellation', $subscriptionEntity, $currentUser);
                $this->output::addMessage('subscription.suspend', 'success', 'Subscription #'.$subscriptionEntity->id.' will be disabled on ' . $args['cancellationDate']);
            } else {
                $subscriptionService = new subscriptionService();
                $subscriptionService->suspendSubscription($subscriptionEntity, 'manual_subscription_suspension', null, "Cancelled by ".$currentUser->getNiceName());
                $this->output::addMessage('subscription.suspend', 'success', 'Subscription #'.$subscriptionEntity->id.' will be disabled imminently.');
            }
            $this->output::addMetadata('subscription.suspend', 'reloadPage', '#');
            //$this->output::addMetadata('subscription.suspend', 'refreshByTag', ['user-subscriptions-table']);
        }

        return System::asJson($response, []);
    }

    public function reenableSubscription(Request $request, Response $response, $args)
    {
        $subscriptionEntity = new subscriptionEntity();
        $subscriptionEntity->load($args['id']);

        $currentUser = currentUser::getCurrentUser();
        if(!$currentUser->isAllowed('ManageUsers') && !$currentUser->isAllowed('UpdateSubscriptions') && $currentUser->id != $subscriptionEntity->user_id) {
            return System::asJson($response, [], 403);
        }

        if (isset($subscriptionEntity) && $subscriptionEntity->id == $args['id']) {
            $subscriptionEntity->enabled = 1;
            $subscriptionEntity->cancellation_date = null;
            $subscriptionEntity->store();
            $this->output::addMessage('subscription.reenable', 'success', 'Subscription #'.$subscriptionEntity->id.' has been re-enabled.');
            //$this->output::addMetadata('subscription.reenable', 'refreshByTag', ['user-subscriptions-table']);
            $this->output::addMetadata('subscription.reenable', 'reloadPage', '#');
        }

        return System::asJson($response, []);
    }


    public function remoteUpdate(Request $request, Response $response, $args)
    {
        $body = $request->getParsedBody();
        if (!isset($body->subscriptionId) || !$body->subscriptionId || !isset($body->remoteKey) || !isset($this->config->app->remoteUpdates->key) || $body->remoteKey != $this->config->app->remoteUpdates->key) {
            $this->output::addMessage('subscription.remote.disable', 'error', 'Required information is missing - requirement not stated explicitly for security reasons');
            $this->output::addResponse($request, [], FALSE); // added so we can hook into this elsewhere.
            return System::asJson($response, [], 400);
        }

        $subscriptionEntity = new subscriptionEntity();
        $subscriptionEntity->load((int)$body->subscriptionId);
        if (!isset($subscriptionEntity->id) || !$subscriptionEntity->id) {
            $this->output::addMessage('subscription.remote.disable', 'error', 'Subscription not found');
            $this->output::addResponse($request, [], FALSE); // added so we can hook into this elsewhere.
            return System::asJson($response, [], 400);
        }

        $responseData = [];

        if (isset($body->enabled) && is_bool($body->enabled)) $subscriptionEntity->enabled = $body->enabled;
        if (isset($body->product_price_override)) $subscriptionEntity->product_price_override = $body->product_price_override;
        if (isset($body->product_price_override_ends)) $subscriptionEntity->product_price_override_ends = $body->product_price_override_ends;
        if (isset($body->credits) && is_array($body->credits)) {
            foreach ($body->credits as $credit) {
                $creditEntity = new subscriptionCreditEntity();
                $creditEntity->credit_amount = $credit->amount;
                $creditEntity->subscription_id = (int)$body->subscriptionId;
                $creditEntity->credit_date = $credit->date;
                if (isset($credit->data)) $creditEntity->data = json_encode($credit->data);
                $creditEntity->store();
            }
        }
        if (isset($body->product_name) && $body->product_name != ""){
            $responseData['product_name'] = $body->product_name;
            $productEntity = new productEntity();
            $productEntity->loadByName($body->product_name);
            if (!isset($productEntity->id) || !$productEntity) { // Automatically create new product if it doesn't exist
                $productEntity = new productEntity();
                $productEntity->product_name = $body->product_name;
                $productEntity->price = $body->product_price;
                $productEntity->type = $product->product_type ?? "";
                $productEntity->code = $product->product_code ?? "";
                $productEntity->created = time();
                $productEntity->store();
                $responseData['new_product'] = 'yes';
            }
            $subscriptionEntity->product_id = $productEntity->id;
        };

        $subscriptionEntity->store();

        $responseData['enabled'] = $subscriptionEntity->enabled;

        return System::asJson($response, ['subscriptionsUpdated' => 1, 'data' => $responseData]);
    }
}