<?php

namespace EstatebudConnect\Services;

if (!defined('WPINC')) {
    die();
}

use EstatebudConnect\Configs\App;
use EstatebudConnect\Models\Settings;
use EstatebudConnect\Core\OptionsAPI;
use EstatebudConnect\Core\Cache;
use EstatebudConnect\Core\Log;
use EstatebudConnect\Traits\Singleton;
use EstatebudConnect\Utilities\Helper;

class Estatebud
{
    protected $baseUrl = 'https://api.estatebud.com';
    protected $version = 'v1';
    protected $cache = null;
    protected $cache_key = 'api';
    protected $token;
    protected $locale;
    public $auth_info = null;

    use Singleton;

    public function __construct()
    {
        $api_key = Settings::instance()->get_api_key();

        $this->set_token($api_key);
        $this->set_locale(Helper::get_locale());
    }

    public function set_token($token)
    {
        $this->token = $token;

        return $this;
    }

    public function set_locale($locale)
    {
        $this->locale = $locale;

        return $this;
    }

    function check_authentication()
    {
        $result = $this->get('whois');
        if ($result) {
            if (isset($result->error)) {
                OptionsAPI::instance()->update('estatebud_api_whois', null);
                $this->auth_info = null;
                return false;
            } else {
                $this->auth_info = $result;
                OptionsAPI::instance()->update('estatebud_api_whois', $result);
                return true;
            }
        } else {
            echo 'Estatebud API server: Communication error';
            return false;
        }
    }

    public function whois()
    {
        $result = $this->get('whois');
        // TODO: temporary fix for start
        if (is_string($result)) {
            $decoded = json_decode($result, true);
            if (is_array($decoded)) {
                $result = $decoded;
            } else {
                return false;
            }
        }
        //temporary
        if (empty($result) || is_int($result) || !is_array($result) || isset($result['error'])) {
            return false;
        }

        return $result;
    }

    public function new_deal(array $params = [])
    {
        return $this->post('newDeal', $params);
    }

    public function get_pipelines(array $params = [])
    {
        return $this->get('getPipelines', $params);
    }

    public function get_currency_rates(array $params = [])
    {
        return $this->get('getCurrency', $params);
    }

    public function get_fields(array $params = [])
    {
        $fields = $this->get('getFields', $params);
        $parsed_fields = [];

        foreach ($fields as $field) {
            $parsed_options_in_field = [];

            if (isset($field['options'])) {
                $checked_options_in_field = is_array($field['options'] ?? null)
                    ? $field['options']
                    : array_values((array) $field['options']);

                foreach ($checked_options_in_field as $option) {
                    $parsed_options_in_field[] = [
                        'value' => $option['value'],
                        'label' => Helper::get_term_from_array($option),
                    ];
                }
            }

            $parsed_fields[] = [
                'name' => $field['name'],
                'type' => $field['type'],
                'options' => $parsed_options_in_field,
                'filter' => $field['filter'] ?? null,
                'label' => Helper::get_term_from_array($field),
            ];
        }

        return $parsed_fields;
    }

    public function get_property_areas(array $params = [])
    {
        return $this->get('getAreas', $params);
    }

    public function get_projects(array $params = [])
    {
        return $this->get('getProjects', $params);
    }

    public function get_project(mixed $id, array $params = [])
    {
        return $this->get("getProject/$id", $params);
    }

    public function get_properties(array $params = [])
    {
        return $this->get('getProperties', $params);
    }

    public function get_property(mixed $id, array $params = [])
    {
        return $this->get("getProperty/$id", $params);
    }

    public function get_property_categories(array $params = [])
    {
        return $this->get('getPropertyCategories', $params);
    }

    public function get_property_types(array $params = [])
    {
        return $this->get('getPropertyTypes', $params);
    }

    public function get_property_pdf_templates(array $params = [])
    {
        return $this->get('getPropertyPDFTemplates', $params);
    }

    public function get_property_pdf(array $params = [])
    {
        return $this->get('getPropertyPDF', $params);
    }

    public function get_property_statuses(array $params = [])
    {
        return $this->get('getPropertyStatuses', $params);
    }

    public function get_similar_properties(mixed $propertyId, array $params = [])
    {
        return $this->get("getSimilarProperties/$propertyId", $params);
    }

    public function get_property_labels(array $params = [])
    {
        return $this->get('getPropertyLabels', $params);
    }

    protected function get(string $endpoint, array $urlParams = [])
    {
        return $this->call('GET', $endpoint, $urlParams);
    }

    protected function post(string $endpoint, array $urlParams = [], array $payload = [])
    {
        return $this->call('POST', $endpoint, $urlParams, $payload);
    }

    protected function call(string $method, string $endpoint, array $urlParams = [], array $payload = [])
    {
        if (!isset($urlParams['language'])) {
            $urlParams['language'] = $this->locale;
        }

        $url =
            "$this->baseUrl/$this->version/$endpoint" .
            (count($urlParams) > 0 ? '?' . http_build_query($urlParams) : '');
        $args = [
            'headers' => [
                'Accept' => 'application/json',
                'Content-Type' => 'application/json',
                'Authorization' => 'Bearer ' . $this->token,
            ],
            'user-agent' => sprintf('WordPress/%s; %s', App::NAME, App::VERSION),
            'method' => $method,
            'timeout' => 30,
        ];

        if ($method == 'POST' && count($payload)) {
            $args['body'] = wp_json_encode($payload);
        }

        if ($method == 'GET' && $this->cache) {
            $cacheId = $this->cache_key . '_' . hash('xxh64', $url . serialize($args));

            $data = Cache::instance()->get($cacheId);
        }

        if (empty($data)) {
            $response = wp_remote_request($url, $args);
            $responseHttpCode = wp_remote_retrieve_response_code($response);
            $data = wp_remote_retrieve_body($response);

            if ($responseHttpCode == 200) {
                $data = $this->parse($data);

                if (isset($cacheId)) {
                    Cache::instance()->set($cacheId, $data, $this->cache);
                }
            }

            Log::write(
                "Estatebud API: HTTP/$method $this->version/$endpoint responded with status $responseHttpCode",
                $urlParams,
            );
        } else {
            Log::write("Estatebud API: Cached data exists $this->version/$endpoint", $cacheId);
        }

        $this->cache = null;

        return $data ?? $responseHttpCode;
    }

    public function cache($duration = 60)
    {
        $this->cache = $duration;

        return $this;
    }

    protected function parse(string $json)
    {
        return json_decode($json, true);
    }
}
