<?php

namespace Inside\DESK\Services;

use Inside\Facades\Http;
use Illuminate\Support\Facades\Config;

use function Couchbase\defaultDecoder;

class SalesForceService
{
    protected array $config;
    protected string $token;

    public function __construct()
    {
        $this->config = Config::get('salesforce_api');
        $this->token = $this->authenticate();
    }

    /**
     * @throws \Exception
     */
    public function getTasksByCodeFra(string $codeFra, string $category = null): array
    {
        $query = "SELECT AGO_HotelName__c,CreatedDate,id,Subject, AGO_INT_Category__c, HQ_Rejection__c, ActivityDate, Status FROM TASK WHERE ";
        if ($category) {
            $query .= "AGO_INT_Category__c = '".$category."' AND ";
        }
        $query .= "Hotel__r.Property_Code__c = '$codeFra' AND Status = 'Open' AND WhoId != null order by ActivityDate, CreatedDate";

        return $this->sendQuery($query);
    }

    /**
     * @throws \Exception
     */
    public function getTask(string $taskId): array
    {
        return $this->sendRequest('GET', $this->buildUrl("/sobjects/Task/$taskId"), []);
    }

    /**
     * @throws \Exception
     */
    public function getCategories(): array
    {
        $query = 'SELECT AGO_INT_Category__c FROM TASK GROUP BY AGO_INT_Category__c';
        $data = $this->sendQuery($query);
        $records = collect($data['records'] ?? []);
        return $records->pluck('AGO_INT_Category__c')->filter()->values()->toArray();
    }

    public function completeTask(array $tasks): array
    {
        $apiVersion = $this->config['version'];
        $compositeRequest = collect($tasks)->map(function ($id) use ($apiVersion) {
            return [
                "method" => "PATCH",
                "url" => "/services/data/v$apiVersion/sobjects/Task/$id",
                "referenceId" => $id,
                "body" => [
                    "Status" => "Terminated"
                ]
            ];
        })->all();

        $payload = [
            "allOrNone" => true,
            "compositeRequest" => $compositeRequest
        ];

        return $this->sendRequest('POST', $this->buildUrl("/composite"), $payload);
    }

    public function updateTaskComment(string $taskId, string $comment): array
    {
        return $this->sendRequest('PATCH', $this->buildUrl("/sobjects/Task/$taskId"), [
            'Follow_up_comment__c' => $comment
        ]);
    }

    public function updateTask(string $taskId, string $body): array
    {
        return $this->sendRequest('PATCH', $this->buildUrl("/sobjects/Task/$taskId"), json_decode($body, true));
    }

    /**
     * @throws \Exception
     */
    private function sendQuery(string $query): array
    {
        $url = $this->buildUrl('/query', ['q' => $query]);
        return $this->sendRequest('GET', $url, []);
    }

    private function sendRequest(string $method, string $endpoint, array $data = []): array
    {
        $url = $this->config['url'] . $endpoint;
        $http = match ($method) {
            'POST','PATCH' => Http::withToken($this->token)->{$method}($url, $data),
            default => Http::withToken($this->token)->{$method}($url),
        };

        if (!$http->successful()) {
            $error = json_decode($http->body(), true);
            throw new \Exception($error[0]['message'] ?? $http->body());
        }

        return json_decode($http->body(), true) ?? [];
    }

    private function buildUrl(string $endpoint, array $params = []): string
    {
        $url = '/services/data/v' . $this->config['version'] . $endpoint;
        if (!empty($params)) {
            $url .= '?' . http_build_query($params);
        }
        return $url;
    }

    private function authenticate(): string
    {
        $response = Http::asForm()->post($this->config['url'].'/services/oauth2/token', [
            'grant_type' => 'client_credentials',
            'client_id' => $this->config['client_id'],
            'client_secret' => $this->config['client_secret'],
        ]);

        return $response['access_token'];
    }
}
