<?php

namespace App\Http\Controllers\Network\Classes;

use Carbon\Carbon;
use Exception;
use GuzzleHttp\Client;
use Illuminate\Support\Arr;
use Illuminate\Support\Facades\Log;
use Yajny\Member\Models\AmazonOrderLog;
use Yajny\Member\Models\AmazonReadLog;

abstract class BaseAmazon implements SalesGetterApi
{
    public $client;
    public $sales;
    private $networkID;

    public function __construct($networkID)
    {
        $this->client = new Client();
        $this->sales = [];
        $this->networkID = $networkID;
    }

    abstract protected function getFileName($dateToFetch): string;
    abstract protected function getTrackingID(): string;
    abstract protected function getClientID(): string;
    abstract protected function getClientSecret(): string;
    abstract protected function getCurrencyCode(): string;
    abstract protected function getMarketplace(): string;

    protected function getToken(): string {
        $tokenResponse = $this->client->post('https://creatorsapi.auth.eu-south-2.amazoncognito.com/oauth2/token', [
            'form_params' => [
                'grant_type' => 'client_credentials',
                'scope' => 'creatorsapi/default',
                'client_id' => $this->getClientID(),
                'client_secret' => $this->getClientSecret()
            ]
        ]);
        return json_decode($tokenResponse->getBody()->getContents())->access_token;
    }
    protected function getReport(string $dateToFetch) {
        $token = $this->getToken();
        $fileName = $this->getFileName($dateToFetch);
        $headers = [
            'Authorization'=> "Bearer $token,Version 2.2",
            'x-marketplace' => $this->getMarketplace()
        ];
        $fileResponse = $this->client->request('POST', 'https://creatorsapi.amazon/reports/v1/getReport?partnerTag=' . $this->getTrackingID(), [
            'headers' => $headers,
            'json' => [
                'filename' => $fileName
            ]
        ]);
        $fileUrl = json_decode($fileResponse->getBody()->getContents())->url;

        $salesCompressedResponse = $this->client->get($fileUrl);
        $compressedResponse = $salesCompressedResponse->getBody()->getContents();
        if(!$compressedResponse) {
            throw new Exception('Unexpected Empty Response');
        }
        return $compressedResponse;
    }

    public function getSales($start_days, $end_days)
    {
        Log::debug('AMAZON_EG_DEBUGGER::getSales', [
            'cli' => app()->runningInConsole(),
            'request' => request(),
            'trace' => debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS),
        ]);
        try {
            $sales = [];
            $dateToFetch = '2021-09-01';
            $lastFailed = AmazonReadLog::where('is_processed', false)->where('network_id', $this->networkID)->first();

            $isFailedDate = false;
            if ($lastFailed) {
                $dateToFetch = $lastFailed->file_date;
                $isFailedDate = true;
            } else {
                $lastFetchedDate = AmazonReadLog::where('is_processed', true)->where('network_id', $this->networkID)->max('file_date');
                $dateToFetch = date('Y-m-d', strtotime(($lastFetchedDate ?? $dateToFetch) . ' + 1 day'));
                //check that we are not trying to get today's file since Amazon uploads the reports delayed 1 day
                if ($dateToFetch == date('Y-m-d'))
                    return [];
            }

            $nextFileDate = date('Ymd', strtotime($dateToFetch));

            $compressedResponse = $this->getReport($nextFileDate);

            $checksum = null;
            $itemsCount = null;

            $xmlDecodedResponse = gzdecode($compressedResponse);
            $rawSalesXML = simplexml_load_string($xmlDecodedResponse);
            $rawSales = json_decode(json_encode($rawSalesXML), true);
            $categories = Arr::pluck($rawSales['ProductLine_array']['ProductLine'], 'ProductGroupName', 'GLProductGroupID');
            if (isset($rawSales['Items']['Item'])) {
                $itemsCount = 0;
                $checksum = md5(json_encode($rawSales['Items']['Item']));
                foreach ($rawSales['Items']['Item'] as $key => $item) {
                    if (strval($key) == '@attributes')
                        $saleItem = $item;
                    else
                        $saleItem = $item['@attributes'];
                    if (str_contains($saleItem['SubTag'], '?')) {
                        $saleItem['SubTag'] = trim($saleItem['SubTag'], '?');
                    }
                    if (str_contains($saleItem['SubTag'], ' ')) {
                        $saleItem['SubTag'] = trim($saleItem['SubTag'], ' ');
                    }

                    if (str_contains($saleItem['SubTag'], ',')) {
                        $saleItem['SubTag'] = explode(',', $saleItem['SubTag'])[1];
                    }
                    if (!is_numeric($saleItem['SubTag']))
                        continue;

                    $saleItem['categoryName'] = $categories[$saleItem['Category']] ?? '';
                    if ($saleItem['Qty'] < 0)
                        $saleItem['Type'] = 'Return';

                    if (isset($sales[$saleItem['SubTag']])) {
                        $sales[$saleItem['SubTag']]['items'][] = $saleItem;
                    } else {
                        $sales[$saleItem['SubTag']] = $saleItem;
                        $sales[$saleItem['SubTag']]['currencyCode'] = $this->getCurrencyCode();
                        $sales[$saleItem['SubTag']]['file_date'] = $dateToFetch;
                        $sales[$saleItem['SubTag']]['items'] = [$saleItem];
                    }
                    $itemsCount++;
                }
            }

            if (!$isFailedDate) {
                AmazonReadLog::create([
                    'file_date' => $dateToFetch,
                    'network_id' => $this->networkID,
                    'is_processed' => count($sales) == 0,
                    'total_orders' => count($sales),
                    'total_items' => !is_null($itemsCount) ? $itemsCount : 0,
                    'last_inserted_index' => 0,
                    'items_checksum' => $checksum,
                    'last_check' => now(),
                    'last_import' => now()
                ]);
            } else {
                $lastFailed->total_orders = count($sales);
                $lastFailed->total_items = !is_null($itemsCount) ? $itemsCount : 0;
                $lastFailed->items_checksum = $checksum;
                $lastFailed->last_check = now();
                $lastFailed->last_import = now();
                $lastFailed->save();

                return $this->sales = array_slice(array_values($sales), $lastFailed->last_inserted_index);
            }

            if (!$sales) return [];
            return $this->sales = $sales;

        } catch (Exception $e) {
            return [];
        }
    }
}
