<?php

namespace App\Shopify;

use App\Helpers\StringHelper;
use App\Models\Order;
use App\Models\User;
use App\SAP\SAPService;
use RuntimeException;

/**
 * Service class serves integration dashboard for order related logic
 */
class OrdersService
{
    const ORDERS_PER_PAGE = 20;
    const SORT_BY_MAPPING = [
        'date' => 'CREATED_AT',
        'shopifyFinStatus' => 'FINANCIAL_STATUS',
        'shopifyFulStatus' => 'FULFILLMENT_STATUS'
    ];

    public function __construct(SAPService $sapSevice)
    {
        $shopifyStore = config('shopify-app.sync_store');
        $this->shop = User::where('name', $shopifyStore)->first();
        if (!$this->shop) {
            throw new RuntimeException('Shopify store not found! Perhaps not installed yet? - ' . $shopifyStore);
        }
        $this->api = $this->shop->api();
        $this->langs = config('shopify-app.available_languages');
        $this->defaultLang = config('shopify-app.default_language');
        $this->sapSevice = $sapSevice;
    }

    public function listOrders($paginationData)
    {
        $pagination = '';

        if (!empty($paginationData['direction']) && $paginationData['direction'] === 'prev') {
            $pagination .= 'last: $numOrders, before: $cursor';
        } else {
            $pagination .= 'first: $numOrders, after: $cursor';
        }

        if (!empty($paginationData['sortBy'])) {
            $sortBy = 'sortKey: ' . self::SORT_BY_MAPPING[$paginationData['sortBy']] . ', reverse: ' .
                (!empty($paginationData['sortDesc']) && $paginationData['sortDesc'] ? 'true' : 'false');
        } else {
            $sortBy = 'sortKey: CREATED_AT, reverse: true';
        }

        $query = '
            query ($numOrders: Int!, $cursor: String){
                orders(' . $pagination . ', query: "status:open AND NOT financial_status:pending AND NOT financial_status:expired", ' . $sortBy . ') {
                    edges {
                        cursor
                        node {
                            id,
                            displayFinancialStatus,
                            displayFulfillmentStatus,
                            fulfillable,
                            name,
                            createdAt
                        }
                    }
                    pageInfo {
                        hasNextPage
                        hasPreviousPage
                    }
                }
            }
        ';

        $response = $this->api->graph($query, [
            'numOrders' => self::ORDERS_PER_PAGE,
            'cursor' => !empty($paginationData['cursor']) ? $paginationData['cursor'] : null
        ]);

        if (($response['status'] !== 200 && $response['status'] !== 201) || $response['errors']) {
            $msg = "Unable to get pending orders from shopify: " . json_encode($response['errors']);
            throw new RuntimeException($msg);
        }

        $pendingOrders = $response['body']['data']['orders']['edges'];
        $pageInfo = $response['body']['data']['orders']['pageInfo'];

        $outputOrders = [];
        $firstCursor = null;
        $lastCursor = null;
        foreach($pendingOrders as $order) {
            $firstCursor = $firstCursor ?? $order['cursor'];
            $lastCursor = $order['cursor'];
            $order = $order['node'];
            $outputOrders[] = [
                'shopifyId' => StringHelper::getIdFromGid($order['id']),
                'shopifyFinStatus' => $order['displayFinancialStatus'],
                'shopifyFulStatus' => $order['displayFulfillmentStatus'],
                'fulfillable' => $order['fulfillable'],
                'orderName' => $order['name'],
                'date' => $order['createdAt'],
                'integrationId' => null,
                'sapId' => null,
                'toSync' => null,
                'toSyncStatus' => null,
                'syncStatus' => 'PENDING',
            ];
        }

        $shopifyIds = array_column($outputOrders, 'shopifyId');

        $intOrders = Order::whereIn('shopify_id', $shopifyIds)
            ->get()
            ->keyBy('shopify_id');

        foreach($outputOrders as $i => $order) {
            if (empty($intOrders[$order['shopifyId']])) {
                continue;
            }

            $intOrder = $intOrders[$order['shopifyId']];
            $outputOrders[$i]['integrationId'] = $intOrder->id;
            $outputOrders[$i]['sapId'] = $intOrder->sap_order_nr;
            $outputOrders[$i]['toSync'] = $intOrder->to_sync;
            $outputOrders[$i]['toSyncStatus'] = $intOrder->to_sync_status;

            if ($outputOrders[$i]['sapId'] && !$outputOrders[$i]['toSyncStatus'] & !$outputOrders[$i]['toSync']) {
                $outputOrders[$i]['syncStatus'] = 'SYNCED';
            }
        }

        $pageInfo['first'] = $firstCursor;
        $pageInfo['last'] = $lastCursor;

        return [
            'list' => $outputOrders,
            'pageInfo' => $pageInfo
        ];
    }

    public function getOrdersNotIntegrated()
    {
        $query = '
            {
                orders(first:50, query: "status:open AND NOT financial_status:pending AND NOT financial_status:expired AND -tag:int") {
                    edges {
                        node {
                            id
                        }
                    }
                }
            }
        ';

        $response = $this->api->graph($query);

        if (($response['status'] !== 200 && $response['status'] !== 201) || $response['errors']) {
            $msg = "Error getting pending orders from shopify: " . json_encode($response['errors']);
            throw new RuntimeException($msg);
        }

        $orders = [];
        foreach($response['body']['data']['orders']['edges'] as $edge) {
            $orders[] = [
                'id' => $edge['node']['id']
            ];
        }
        return $orders;
    }

    public function countOrdersNotSentToSAP()
    {
        return Order::whereNull('sap_order_nr')
            ->count();
    }

    public function countPendingStatusUpdate()
    {
        return Order::where('to_sync_status', true)
            ->count();
    }
}
