<?php

namespace apexl\Io\modules\payment\services;

use apexl\Config\Singleton;
use apexl\encryption\Encrypt;
use apexl\Io\includes\Hook;
use apexl\Io\includes\Routes;
use apexl\Io\modules\company\entities\companyEntity;
use apexl\Io\modules\email\services\emailService;
use apexl\Io\modules\email\services\templateService;
use apexl\Io\modules\payment\entities\paymentEntity;
use apexl\Io\modules\payment\entities\paymentProviderRefEntity;
use apexl\Io\modules\payment\entities\paymentTokenEntity;
use apexl\Io\modules\payment\providers\stripeProvider;
use apexl\Io\modules\product\entities\productEntity;
use apexl\Io\modules\subscription\entities\subscriptionEntity;
use apexl\Io\modules\user\entities\userEntity;
use apexl\Io\modules\user\services\simService;
use apexl\Io\modules\user\services\userTools;
use apexl\Io\services\Logger;
use apexl\Io\services\Mailer;
use apexl\Io\services\Output;
use apexl\Io\services\pathUtility;
use apexl\Utils\Urls\Host;
use Psr\Http\Message\ServerRequestInterface as Request;
//use n1ghteyes\apicore\client;
use GuzzleHttp\Client;

class woocommerceIntegrationService {

    protected $config;
    
    public function __construct()
    {
        $this->config = Singleton::getInstance();
    }

    public function hasWoocommerceIntegration()
    {
        return !is_null($this->getWoocommerceApiUrl());
    }

    protected function getProductNameForId($productId)
    {
        if (!isset($productNames)) {
            static $productNames;

            $productEntity = new productEntity();
            $productNames = $productEntity->getProductNameCache();

        }

        return $productNames[$productId] ?? null;
    }

    public function createOrder($userId, $totalNet, $totalTax, $lineItems, $status, $chargeId)
    {
        $userEntity = new userEntity();
        $userEntity->load($userId);

        // @Todo get product cache

        $order = (object)[
            "payment_method" => "card",
            "billing" => (object)[
                "first_name" => $userEntity->first_name,
                "last_name" => $userEntity->last_name,
                "email" => $userEntity->email,
            ],
            "status" => $status,
            "line_items" => [

            ]
        ];
        if ($chargeId) $order->transaction_id = $chargeId;

        foreach ($lineItems as $item) {

            $productEntity = new productEntity();
            $productEntity->load($item->productId);

            $order->line_items[] = (object)[
                "name" =>  $this->clean("Subscription payment for {$this->getProductNameForId($item->productId)} - {$item->description}"),
                "product_id" => $productEntity->frontend_id ?? null,
                "quantity" => (string)$item->quantity,
                "subtotal" => (string)($item->amount),
                "total" => (string)($item->amount),
                //"total_tax" => $item->vat,
                "tax_class" => "",
                "meta_data" => [
                    (object)[
                        'key' => "dash_subscription",
                        'value' => $item->productId
                    ]
                ]
            ];
        }

        if ($apiUrl = $this->getWoocommerceApiUrl()) {
            $response = $this->makeRequest('POST', $apiUrl.'orders', $order);
            $order = json_decode($response);
            if (isset($order->id)) {
                return $order->id;
            }
        }

        return false;
    }

    public function updateOrder($wpPostId, $billingAddress=null, $shippingAddress=null)
    {
        $data = (object)[];
        if ($billingAddress) {
            $data->billing = $billingAddress;
        }
        if ($shippingAddress) {
            $data->shipping = $shippingAddress;
        }

        if ($billingAddress || $shippingAddress) {
            if ($apiUrl = $this->getWoocommerceApiUrl()) {
                $response = $this->makeRequest('PUT', $apiUrl . 'orders/'.$wpPostId, $data);
            $order = json_decode($response);
            if (isset($order->id)) {
                return $order->id;
            }
        }
        }

        return false;
    }

    public function fetchOrders($startDate=null, $perPage=100)
    {
        // e.g. https://example.com/wp-json/wc/v3/orders?consumer_key=ck_xxx&consumer_secret=cs_xxx&status=completed&after=2021-11-30&before=2021-12-02
        if ($apiUrl = $this->getWoocommerceApiUrl()) {
            $queryStr = '?per_page='.$perPage.'&orderby=date&order=asc';
            if ($startDate) $queryStr .= '&modified_after='.$startDate;

            return $this->makeGetRequest($apiUrl.'orders'.$queryStr);
        }
    }

    public function fetchOrderNotes($post, $startDate=null, $perPage=100)
    {
        if ($apiUrl = $this->getWoocommerceApiUrl()) {
            $queryStr = '?per_page='.$perPage.'&orderby=modified&order=asc';
            if ($startDate) $queryStr .= '&after='.$startDate;

            return $this->makeGetRequest($apiUrl.'orders/'.$post.'/notes'.$queryStr);
        }
    }

    public function fetchComments($post, $startDate=null, $perPage=100)
    {
        if ($apiUrl = $this->getWordpressApiUrl()) {
            $queryStr = '?per_page='.$perPage.'&order=asc&post='.$post;
            if ($startDate) $queryStr .= '&after='.$startDate;

            return $this->makeGetRequest($apiUrl.'comments'.$queryStr);
        }
    }

    public function fetchProducts($id=0, $perPage=100, $status='publish')
    {
        if ($apiUrl = $this->getWoocommerceApiUrl()) {
            $queryStr = '?per_page='.$perPage.'&orderby=date&order=asc';
            if ($id) $queryStr .= '&id='.$id;
            if ($status) $queryStr .= '&status='.$status;

            return $this->makeGetRequest($apiUrl.'products'.$queryStr);
        }
    }

    public function getUserByEmail($email)
    {
        // e.g. https://example.com/wp-json/wp/v2/users/?search=myemail@domain.com
        if ($apiUrl = $this->getWoocommerceApiUrl()) {
            $queryStr = '?email='.$email;
            $results = $this->makeGetRequest($apiUrl.'customers'.$queryStr);
            return $results[0] ?? null;
        }
    }

    protected function clean($string)
    {
        $string = trim(preg_replace('/\s\s+/', ' ', $string));
        $string = str_replace("\n", "", $string);
        return $string;
    }

    public function validateRemoteProductIds($productData)
    {
        if (!$this->hasWoocommerceIntegration()) return true;

        if (is_array($productData)) {
            foreach ($productData as $product) {
                if (!isset($product->product_id) && $product->product_id != '0') return false; // product id must be provided,  allow "0" for e.g. shipping

                $productEntity = new productEntity();
                $productEntity->loadByFrontendId($product->product_id);
                if ($product->product_id > 0 && (!isset($productEntity->id) || !$productEntity->id)) return false; // No ID mapping found for woocommerce product
            }
        }

        return true;
    }

    public function setOrderStatus($orderId, $status, $tokenIv='')
    {
        if ($webhookUrl = $this->getWoocommerceWebhookUrl()) {
            $this->makeGetRequest($webhookUrl.'&order_id='.$orderId.'&status='.$status.'&dashTokenIv='.$tokenIv);
        }
    }

    public function notifyOrderSuccess($orderId, $chargeId)
    {
        if ($webhookUrl = $this->getWoocommerceWebhookUrl()) {
            $this->makeGetRequest($webhookUrl.'&order_id='.$orderId.'&charge_id='.$chargeId);
        }
    }

    protected function getWoocommerceWebhookUrl()
    {
        return $this->config->app->payments->woocommerce->webhook ?? null;
    }

    protected function getWoocommerceApiUrl()
    {
        return $this->config->app->payments->woocommerce->api_url ?? null;
    }

    protected function getWordpressApiUrl()
    {
        return $this->config->app->wordpress->api->base_url ?? null;
    }

    protected function makeGetRequest($url)
    {
        try {
            $client = new Client(['verify' => false, 'timeout' => 10]);
            $response = $client->request('GET', $url, [
                'auth' => [
                    $this->config->app->payments->woocommerce->consumer_key,
                    $this->config->app->payments->woocommerce->consumer_secret
                ]
            ]);
            $contents = $response->getBody()->getContents();

            Logger::log('woocommerce_request', [
                'url' => $url,
                'method' => 'GET',
                'response' => $contents,
                'statusCode' => $response->getStatusCode(),
            ]);

            return json_decode($contents);
        } catch (\Exception $e){
            Logger::log('woocommerce_request', [
                'url' => $url,
                'method' => 'GET',
                'error' => $e->getMessage(),
            ]);
            error_log('[WooCommerceIntegration makeGetRequest('.$url.')] FAILED - with - '.$e->getMessage());
        }
        return null;

    }

    protected function makeRequest($method='POST', $url, $data)
    {
        try {

            $logData = (object)[
                'url' => $url,
                'data' => $data
            ];
            Logger::log('woocommerce_'.strtolower($method).'_request', $logData);

            $client = new Client(['verify' => false, 'timeout' => 10]);
            $response = $client->request($method, $url, [
                'body' => json_encode($data),
                'auth' => [
                    $this->config->app->payments->woocommerce->consumer_key,
                    $this->config->app->payments->woocommerce->consumer_secret
                ],
                'headers' => [
                    'Content-Type' => 'application/json'
                ]
            ]);
            $contents = $response->getBody()->getContents();

            $logData->response = json_decode($contents);
            Logger::log('woocommerce_'.strtolower($method).'_request_response', $logData);

            return $contents;
        } catch (\Exception $e){
            echo $e->getMessage();
            $logData->error = $e->getMessage();
            Logger::log('woocommerce_'.strtolower($method).'_request_error', $logData);
            error_log('[WooCommerceIntegration makeRequest('.$method.': '.$url.')] FAILED - with - '.$e->getMessage());
        }

        return null;

    }

    public function orderPlacementFailureNotification($subscriptionId)
    {

        $frontEndDomain = $this->config->app->site->frontend_domain ?? 'localhost';

        $emailService = new emailService();
        $result = $emailService->send(
            (object) [
                'to' => '[WEBMASTER]',
                'subject' => 'Order Creation Failure Notification',
                'body' => 'The GlobalM2MSim Dashboard failed to create an order in Woocommerce after processing Subscription ID:'.$subscriptionId,
                'user_id' => 0,
            ],
            'none'
        );
    }



    /*  NOT SURE IF THIS WILL BE NEEDED AT ALL FOR PROD - SPOTTED IT ONLINE
     public function handle(Request $request, Closure $next)
    {

        $hmac = $request->get('hmac');

        $signature = Request::header('x-wc-webhook-signature');
        $woocommerceData = $request->get('woocomerceData');
        $get_hmac = hash_hmac('sha256', $woocommerceData, $secret, true);

        $get_hmac = base64_encode($get_hmac)

        if ($hmac == $get_hmac) {
            return $next($request);
        }
        else {
            return false;
        }
    }
     */
}