<?php

namespace WPIS;

include_once $_SERVER['DOCUMENT_ROOT'] . '/wp-config.php';
include_once $_SERVER['DOCUMENT_ROOT'] . '/wp-load.php';
include_once $_SERVER['DOCUMENT_ROOT'] . '/wp-includes/class-wpdb.php';
include_once $_SERVER['DOCUMENT_ROOT'] . '/wp-includes/pluggable.php';

class ImmosyncClient
{

    private $apiUrl = WPIS::API_URL . '/realestate/';

    private $headers = [];
    private $errors = [];

    static public function init()
    {

        $class = new self();

        $class->headers[] = 'Cache-Control: no-cache';
        $class->headers[] = 'Accept: application/json';
        $class->headers[] = 'Content-Type: application/json';

        add_action('wp_ajax_nopriv_wpis_' . 'createContact', [$class, 'createContact']);
        add_action('wp_ajax_wpis_ ' . 'createContact', [$class, 'createContact']);

        return $class;
    }


    public function request(string $method, string $endpoint, array $payload = [])
    {

        $payload['wpis_version'] = get_plugin_data(__DIR__ . '/../wp-immo-sync.php')['Version'];
        $payload['wp_version']   = get_bloginfo('version');;
        $payload['referer']      = $_SERVER['HTTP_HOST'];

        if ($endpoint !== 'renew-token') {
            $this->auth();
        }

        $method = strtoupper($method);

        $params = http_build_query($payload);
        $curl = curl_init();

        $options = [
            CURLOPT_URL => $this->apiUrl . $endpoint . '?' . $params,
            CURLOPT_RETURNTRANSFER => true,
            CURLOPT_MAXREDIRS => 10,
            CURLOPT_TIMEOUT => 30,
            CURLOPT_CUSTOMREQUEST => $method,
            CURLOPT_HTTPHEADER => $this->headers,
        ];

        if ($method === 'POST') {
            $options[CURLOPT_POST] = true;
            $options[CURLOPT_POSTFIELDS] = http_build_query($payload);
        }

        curl_setopt_array($curl, $options);

        $response = curl_exec($curl);
        $err = curl_error($curl);
        $httpcode = curl_getinfo($curl, CURLINFO_HTTP_CODE);
        curl_close($curl);

        if ($err)
            return (object) ['error' => true, 'message' => "cURL Error : " . $err];

        return (object) ['code' => $httpcode, 'data' => $response];
    }

    private function response($code, $data = false)
    {
        http_response_code($code);
        header('Content-Type: application/json');
        if ($data) {
            echo json_encode($data);
        }
        exit;
    }

    private function auth()
    {

        $connectionInfo = DatabaseManager::db()->get_results('SELECT * FROM ' . DatabaseManager::db()->prefix . WPIS::WP_TABLE_CONNEXION . ' LIMIT 1');

        if (empty($connectionInfo)) {
            $this->errors = 'Wordpress is not connected to ImmoSync.';
            return $this;
        }

        $token = $connectionInfo[0]->token;

        if ($this->isTokenExpired($token)) {
            $token = $this->renewToken($token);
        }

        $protocol = (!empty($_SERVER['HTTPS']) && $_SERVER['HTTPS'] !== 'off' || $_SERVER['SERVER_PORT'] == 443) ? "https://" : "http://";

        $this->headers[] = 'Access-Control-Allow-Origin: ' . $protocol . $_SERVER['HTTP_HOST'];
        $this->headers[] = 'Authorization: Bearer ' . $token;

        return $this;
    }

    private function isTokenExpired($token)
    {
        $tokenParts = explode('.', $token);
        $tokenPayload = json_decode(base64_decode($tokenParts[1]));

        return $tokenPayload->exp < time();
    }

    private function renewToken()
    {
        $connectionInfo = DatabaseManager::db()->get_row('SELECT * FROM ' . DatabaseManager::db()->prefix . WPIS::WP_TABLE_CONNEXION . ' LIMIT 1');
        $expiredToken = $connectionInfo->token;
        $accessId = $connectionInfo->access_id;

        $this->apiUrl = WPIS::API_URL . '/wordpress/';
        $request = $this->request('POST', 'renew-token', ['token' => $expiredToken, 'accessId' => $accessId]);
        $this->apiUrl = WPIS::API_URL . '/realestate/';

        $apiResponse = json_decode($request->data);

        if ($apiResponse->success !== true) {
            $this->errors = $apiResponse->message;
            return $this;
        }

        DatabaseManager::db()->update(
            DatabaseManager::db()->prefix . WPIS::WP_TABLE_CONNEXION,
            ['token' => $apiResponse->data->token],
            ['access_id' => $accessId]
        );

        return $apiResponse->data->token;
    }

    public function enableSyncAutomation()
    {
        $this->apiUrl = WPIS::API_URL . '/wordpress/';
        $connectionInfo = DatabaseManager::db()->get_results('SELECT * FROM ' . DatabaseManager::db()->prefix . WPIS::WP_TABLE_CONNEXION . ' LIMIT 1');
        $accessId = $connectionInfo[0]->access_id;
        $cronKey = SettingsManager::get('cronKey');
        $response = $this->request('POST', 'enable-auto-sync', ['accessId' => $accessId, 'cronKey' => $cronKey]);

        $this->response(200, json_decode($response->data));
    }

    public function disableSyncAutomation()
    {
        $this->apiUrl = WPIS::API_URL . '/wordpress/';
        $connectionInfo = DatabaseManager::db()->get_results('SELECT * FROM ' . DatabaseManager::db()->prefix . WPIS::WP_TABLE_CONNEXION . ' LIMIT 1');
        $accessId = $connectionInfo[0]->access_id;
        $response = $this->request('POST', 'disable-auto-sync', ['accessId' => $accessId]);

        $this->response(200, json_decode($response->data));
    }

    public function createContact($formdata = null)
    {

        $payload = $formdata ?? json_decode(file_get_contents('php://input'));

        $acceptedSource = ['searchForm', 'contactForm', 'estateForm', 'evaluationForm'];

        Logger::log('wpis-contact', [
            '[NEW CONTACT]',
            '> type: ' . ($formdata ? 'api' : 'webhook'),
            '> form: ' . $payload->source,
            '> rawInput: ' . json_encode($payload),
        ]);

        if (!isset($payload->source) || !in_array($payload->source, $acceptedSource)) {
            Logger::log('wpis-contact', '> error: ' . 'Contact source is not valid');

            if ($formdata) {
                return ['success' => false, 'data' => 'Contact source is not valid'];
            } else {
                return $this->response(422, ['success' => false, 'data' => 'Contact source is not valid']);
            }
        }

        $searchZips = [];
        foreach ([1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25] as $zipKey) {
            if (isset($payload->{'searchZipCode' . $zipKey}) && $payload->{'searchZipCode' . $zipKey}) {
                $searchZips[] = $payload->{'searchZipCode' . $zipKey};
            }
        }

        $input = [
            'source'    => $payload->source,
            'phone'     => $payload->phone,
            'firstname' => $payload->firstname,
            'lastname'  => $payload->lastname,
            'gender'    => $payload->gender,
            'language'  => isset($payload->language) ? $payload->language : null,
            'email'     => $payload->email,

            'agreement' => isset($payload->agreement) && $payload->agreement,

            'addressNumber' => $payload->addressNumber,
            'addressZip'    => $payload->addressZip,
            'addressStreet' => $payload->addressStreet,
            'addressCity'   => $payload->addressCity,
            'addressBox'    => $payload->addressBox,

            'message' => $payload->comment ?? $payload->message
        ];

        if ($payload->officeId) {
            $input['officeId'] = $payload->officeId;
        }

        if ($payload->source === 'estateForm') {
            $estateId = isset($payload->estateId) ? $payload->estateId : $payload->estateInterestId;
            $input['estateInterestId'] = $estateId;
            $input['listId'] = $payload->listId;
        }

        if ($payload->source === 'searchForm') {
            if (isset($payload->search)) {
                $input['search'] = [
                    'purpose'    => $payload->search->purpose,
                    'category'   => $payload->search->category,
                    'priceRange' => $payload->search->priceRange,
                    'rooms'      => $payload->search->rooms,
                    'zips'       => $payload->search->zips,
                    'areaMin'    => isset($payload->search->areaMin) ? intval($payload->search->areaMin) : 1,
                    'areaMax'    => isset($payload->search->areaMax) ? intval($payload->search->areaMax) : 10000,
                ];
            } else {
                $input['search'] = [
                    'purpose'    => $payload->searchPurpose,
                    'category'   => $payload->searchCategory,
                    'priceRange' => [$payload->searchPriceMin, $payload->searchPriceMax],
                    'rooms'      => $payload->searchRooms,
                    'zips'       => $searchZips,
                    'areaMin'    => isset($payload->searchAreaMin) ? intval($payload->searchAreaMin) : 1,
                    'areaMax'    => isset($payload->searchAreaMax) ? intval($payload->searchAreaMax) : 10000,
                ];
            }
        }

        Logger::log('wpis-contact', '> formatedInput: ' . json_encode($input));

        $response = $this->request('POST', 'contact', $input, $this->headers);

        Logger::log('wpis-contact', '> response : ' . json_encode($response) . "\n");

        $apiResponse = json_decode($response->data);

        if ($formdata && $apiResponse->success === true) {
            return $apiResponse;
        }

        if ($apiResponse->success !== true) {
            return $this->response(422, ['success' => false, 'response' => $apiResponse]);
        }

        return $this->response(200, ['success' => true, 'contactId' => $apiResponse->contactId]);
    }
}
