<?php

namespace Edoobox\Requests;

use Edoobox\Base\Cache;
use Edoobox\Base\Options;
use Edoobox\Base\Settings;
use Edoobox\Helpers\Arr;
use Edoobox\Requests\Helpers\Request;
use Exception;

class Next {
    private array $attributes;
    private Auth $auth;
    private Settings $settings;

    public function __construct($attributes) {
        $this->attributes = $attributes;
        $this->auth = new Auth();
        $this->settings = new Settings();
    }

    public function fetch(): array {
        return $this->settings->get(Settings::USE_V2) ? $this->fetchV2() : $this->fetchV1();
    }

    public function fetchV1(): array {

        $cacheKey = Page::getCurrentPageCacheKey($this->attributes, true);
        $cache = Cache::get($cacheKey);
        if ($cache) {
            return $cache;
        }

        try {
            $environment = $this->settings->get("environment");
            $query = $this->buildRequestQueryString();

            $apiData = wp_remote_get("https://$environment.edoobox.com/v1/offers$query", [
                'timeout' => Settings::SETTINGS_REQUEST_TIMEOUT
            ]);
            Request::checkResponse($apiData);
            $response = [
                'api' => json_decode($apiData['body'], true),
                'provider_url' => Request::buildProviderUrl($this->attributes['root'])
            ];
            Cache::set($cacheKey, $response, Options::get('edoobox_cache_time_in_s', 0));
            return $response;
        } catch ( Exception $exception ) {
            Request::renderException($exception);
            return [];
        }
    }

    public function fetchV2(): array {

        $cacheKey = Page::getCurrentPageCacheKey($this->attributes, true);
        $cache = Cache::get($cacheKey);
        if ($cache) {
            return $cache;
        }

        try {
            $environment = $this->settings->get(Settings::SETTINGS_ENVIRONMENT);
            $this->auth->authenticate();
            $query = $this->buildRequestQueryString() . "?filter=" .
                json_encode($this->filtersV2()) .
                '&order=[{"property":"date_start","value":"ASC"}]' .
                '&fields=' . json_encode($this->fieldsV2()) .
                '&limit=' . json_encode($this->limitV2());

            $apiData = wp_remote_get("https://$environment.edoobox.com/v2/offer/list$query", [
                'headers' => [
                    "edid" => $this->auth->getEdid(),
                    "language" => $this->attributes["language"],
                    "grant-type" => "access_token",
                    "Authorization" => "Bearer " . $this->auth->getAuthToken()
                ],
                'timeout' => Settings::SETTINGS_REQUEST_TIMEOUT
            ]);

            Request::checkResponse($apiData);

            $mapped = [];
            foreach ( json_decode($apiData['body'], true)['data'] as $offerId => $offer ) {
                $mapped[$offerId] = [
                    "id" => Arr::get($offer, "id"),
                    "name" => Arr::get($offer, "name"),
                    "number" => Arr::get($offer, "number"),
                    "shortdescription" => Arr::get($offer, "shortdescription"),
                    "user_maximum" => Arr::get($offer, "user_maximum"),
                    "user_minimal" => Arr::get($offer, "user_minimal"),
                    "start_date" => Arr::get($offer, "date_start"),
                    "end_date" => Arr::get($offer, "date_end"),
                    "deadline" => Arr::get($offer, "date_close"),
                    "image" => Arr::get($offer, "image.url", ''),
                    "place_id" => Arr::get($offer, "place") ?: null, // Assuming 'place' can be an ID or false
                    "category_id" => Arr::get($offer, "category"),
                    "status" => (string)Arr::get($offer, "status"),
                    "lesson_booking" => Arr::get($offer, "lesson_booking"),
                    "waiting_list" => Arr::get($offer, "waiting_list"),
                    "offer_details_url" => Arr::get($offer, 'shareurl'),
                    "booking_status" => "normal", // This seems to be hardcoded
                    "booking_start_url" => null, // This information was not provided
                ];
            }

            $response = [
                'api' => ['data' => $mapped],
                'provider_url' => Request::buildProviderUrl($this->attributes['root'])
            ];
            Cache::set($cacheKey, $response, Options::get('edoobox_cache_time_in_s', 0));
            return $response;
        } catch ( Exception $exception ) {
            Request::renderException($exception);
            return [];
        }
    }

    private function buildRequestData(): array {
        return [
            "api1" => $this->auth->getPublicKey(),
            "api2" => $this->auth->getSecretKey(),
            "language" => $this->attributes['language'],
            "filter" => [
                "startdate" => [
                    "property" => "offer.startdate",
                    "value" => date('c'),
                    "expression" => ">"
                ],
                "status" => [
                    "property" => "offer.status",
                    "value" => "1,2",
                ]
            ],
            "limit" => [
                "start" => $this->attributes['start'],
                "reply" => $this->attributes['limit']
            ]
        ];
    }

    private function buildRequestQueryString(): string
    {
        $allowedQueries = ['edcode', 'edref', 'edtag', 'edpromo', 'edlanguage', 'edlink', 'edstart', 'edend', 'edview', 'q', 'edfilter'];
        $requestQueries = [];
        $useV2 = $this->settings->get(Settings::USE_V2);

        foreach ( $allowedQueries as $query ) {
            $queryValue = get_query_var($query);
            $valueIsEmpty = $queryValue === '' || $queryValue === null;

            if ( ! $valueIsEmpty ) {
                $requestQueries[$query] = $queryValue;
                continue;
            }

            if ( $query === 'q' && $this->attributes['q'] !== '' ) {
                $requestQueries['q'] = $queryValue;
                continue;
            }

            if ( array_key_exists((string)substr($query, 2), $this->attributes) && $this->attributes[substr($query, 2)] !== '' ) {
                $requestQueries[$query] = $this->attributes[substr($query, 2)];
                continue;
            }

            if ( $query == 'edref' && $this->attributes['label'] !== '' ) {
                $requestQueries[$query] = $this->attributes['label'];
            }
        }

        $requestQueries['cms_data'] = json_encode($this->buildRequestData());

        return count($requestQueries) > 0 && ! $useV2 ? '?' . http_build_query($requestQueries) : '';
    }

    private function fieldsV2(): array {
        return [
            "archive",
            "barcode_ticket",
            "calendar_week",
            "category",
            "checklistPassed",
            "countdown",
            "country",
            "date_close",
            "date_displayend",
            "date_displayend_reference",
            "date_end",
            "date_start",
            "datesLoaded",
            "design",
            "hasDate",
            "id",
            "image",
            "intern_code",
            "internal_code",
            "isExpanded",
            "lesson_booking",
            "mode",
            "multi_offer",
            "multi_offer_child",
            "multiple_registration",
            "mustpay",
            "name",
            "number",
            "offerdef",
            "order",
            "place",
            "row_lft",
            "row_rgt",
            "shareurl",
            "shortdescription",
            "status",
            "tags",
            "trash",
            "type",
            "user_maximum",
            "user_minimal",
            "vat",
            "waiting_list"
        ];
    }

    private function filtersV2(): array {
        return [
            [
                "expression" => "greaterthan",
                "property" => "date_end",
                "value" => date('c')
            ],
            [
                "expression" => "greaterthan",
                "property" => "date_close",
                "value" => date('c')
            ],
            [
                "expression" => "IN",
                "property" => "status",
                "value" => "1,2"
            ]
        ];
    }

    private function limitV2(): array {
        return [
            "start" => 0,
            "reply" => Arr::get($this->attributes, 'limit', 99999)
        ];
    }
}