<?php

namespace App\Services\Integrations\Tickets\Zendesk;

use App\Models\ApiCredential;
use App\Models\FailedTicketHistory;
use Illuminate\Support\Facades\Http;
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\Log;

class OAuthWrapperZendesk
{

    /**
     * Get the API crediantial of this Ticket Service
     * @return [type]
     */
    public function getApiCredential()
    {
        $zendeskCredential = ApiCredential::where('slug', 'zendesk')->first();
        $credentials = [
            'baseUrl' => optional($zendeskCredential)->url,
            'apiToken' => optional($zendeskCredential)->key,
            'userEmail' => optional($zendeskCredential)->user_name,
            'authCredentials' => base64_encode(optional($zendeskCredential)->user_name . '/token:' . optional($zendeskCredential)->key),
            'zendeskCredential' => $zendeskCredential
        ];
        return (object) $credentials;
    }

    /**
     * getAuthorizedUser  - get current user details with auth
     *
     * @return object
     */
    public function getAuthorizedUser()
    {
        $credentials = $this->getApiCredential();
        try {
            $response = Http::withHeaders([
                'Content-Type' => 'application/json',
                'Authorization' => 'Basic ' . $credentials->authCredentials
            ])->get($credentials->baseUrl . 'api/v2/users/me.json')
                ->throw();
            if ($response->successful()) {
                $user = $response['user'];
                if ($user['id']) {
                    return $user;
                }
            }
        } catch (\Exception $e) {
            // dd($e->getMessage());
            logMessage('Zendesk action failed. ' . $e->getMessage(), 'error');
        }
        return false;
    }

    /**
     * getTicket
     *
     * @param  int $ticketId
     * @return json
     */
    public function getTicket($ticketId)
    {
        if (!$this->getAuthorizedUser()) {
            return false;
        }
        $credentials = $this->getApiCredential();

        try {
            return $response = Http::withHeaders([
                'Content-Type' => 'application/json',
                'Authorization' => 'Basic ' . $credentials->authCredentials
            ])->get($credentials->baseUrl . 'api/v2/tickets/' . $ticketId . '.json')
                ->throw();
            if ($response->successful()) {
                return $response;
            }
        } catch (\Exception $e) {
            // dd($e->getMessage());
            logMessage('Zendesk action failed. ' . $e->getMessage(), 'error');
        }

        return false;
    }


    /**
     * createTicket
     *
     * @param  mixed $data
     * @return json
     */
    public function createTicket($data)
    {
        if (!$this->getAuthorizedUser()) {
            return false;
        }
        $credentials = $this->getApiCredential();
        $data = $this->generateFormattedDataForCreateTicket($data);

        try {
            $response = Http::withHeaders([
                'Content-Type' => 'application/json',
                'Authorization' => 'Basic ' . $credentials->authCredentials
            ])->post(
                $credentials->baseUrl . 'api/v2/tickets.json',
                $data
            )->throw();

            if ($response->successful()) {
                return $response;
            }
        } catch (\Exception $e) {
            // dd($e->getMessage());
            logMessage('Zendesk ticket creation failed. ' . $e->getMessage(), 'error');
        }
        return false;
    }

    /**
     * add Comment to ticket
     *
     * @param  int $ticketId
     * @param  string $description
     * @param  int $userId
     * @return json
     */
    public function addComment($ticketId, $description, $userId)
    {
        if (!$this->getAuthorizedUser()) {
            $this->createFailedTicketHistory($ticketId, $userId, $description, 'Unauthorized');
            return false;
        }

        $credentials = $this->getApiCredential();

        $data = $this->generateFormattedData($description);

        try {
            $response = Http::withHeaders([
                'Content-Type' => 'application/json',
                'Authorization' => 'Basic ' . $credentials->authCredentials
            ])->put($credentials->baseUrl . 'api/v2/tickets/' . $ticketId . '.json', $data)
                ->throw();
            if ($response->successful()) {
                return $response;
            }
        } catch (\Exception $e) {
            logMessage('Add comment to ticket failed. ' . $e->getMessage(), 'error');
            $this->createFailedTicketHistory($ticketId, $userId, $description, json_encode($e->getMessage()));
            return false;
        }
    }

    /**
     * generateFormattedData for zendek API
     *
     * @param  string $description
     * @return array
     */
    public function generateFormattedData($description)
    {
        $description = preg_replace(array('/"/', '/\\\/'), '', str_replace('\n', '*newline*', $description));
        $data = [
            "ticket" =>
            [
                "comment" =>
                [
                    "body" => "$description",
                    "public" => false
                ],
            ]
        ];

        // $data = str_replace('*newline*', ' \n ', json_encode($data));
        return $data;
    }

    /**
     * generateFormattedDataForCreateTicket for zendesk
     *
     * @param  array  $data
     * @return array
     */
    public function generateFormattedDataForCreateTicket($data)
    {
        $data = [
            "ticket" => [
                "comment" => [
                    "body" => $data['description'],
                    "public" => false
                ],
                "priority" => "urgent",
                "subject" =>  $data['summary'],
                "is_public" => false,
            ]
        ];
        return $data;
    }

    /**
     * add Attachment to ticket
     *
     * @param  int $ticketId
     * @param  string $description
     * @param  int $userId
     * @return json
     */
    public function addAttachment($ticketId, $description, $userId, $attachemntFIlePath, $fileName)
    {
        if (!$this->getAuthorizedUser()) {
            $this->createFailedTicketHistory($ticketId, $userId, $description, 'Unauthorized');
            return false;
        }
        $credentials = $this->getApiCredential();
        try {
            $response = Http::withHeaders([
                'Content-Type' => 'application/binary',
                'Authorization' => 'Basic ' . $credentials->authCredentials
            ])->withBody(
                file_get_contents($attachemntFIlePath),
                'application/binary'
            )->post($credentials->baseUrl . 'api/v2/uploads.json?filename=' . $fileName)
                ->throw();
            if ($response->successful()) {
                return $response;
            }
        } catch (\Exception $e) {
            // dd($e->getMessage());
            logMessage('Add attachemnt to ticket failed. ' . $e->getMessage(), 'error');
            $this->createFailedTicketHistory($ticketId, $userId, $description, json_encode($e->getMessage()));
            return false;
        }
    }

    /**
     * addComment
     *
     * @param  int $ticketId
     * @param  string $description
     * @param  int $userId
     * @return json
     */
    public function addAttachmenttoComment($ticketId, $description, $userId, $attachmentToken)
    {
        if (!$this->getAuthorizedUser()) {
            $this->createFailedTicketHistory($ticketId, $userId, $description, 'Unauthorized');
            return false;
        }
        $credentials = $this->getApiCredential();
        $data = $this->generateFormattedDataForAttacment($description, $attachmentToken);

        try {
            $response = Http::withHeaders([
                'Content-Type' => 'application/json',
                'Authorization' => 'Basic ' . $credentials->authCredentials
            ])->put($credentials->baseUrl . 'api/v2/tickets/' . $ticketId . '.json', $data)
                ->throw();
            if ($response->successful()) {
                return $response;
            }
        } catch (\Exception $e) {
            logMessage('Add comment to ticket failed. ' . $e->getMessage(), 'error');
            $this->createFailedTicketHistory($ticketId, $userId, $description, json_encode($e->getMessage()));
            return false;
        }
    }

    /**
     * generateFormattedData for attachment
     *
     * @param  string $description
     * @return array
     */
    public function generateFormattedDataForAttacment($description, $attachmentToken)
    {
        $description = preg_replace(array('/"/', '/\\\/'), '', str_replace('\n', '*newline*', $description));
        $data = [
            "ticket" =>
            [
                "comment" =>
                [
                    "body" => $description,
                    "public" => true,
                    "uploads" => [$attachmentToken]
                ],
            ]
        ];

        // $data = str_replace('*newline*', ' \n ', json_encode($data));
        return $data;
    }

    /**
     * Creates an entry to failed ticket histories on exception
     * @param mixed $ticketId
     * @param mixed $userId
     * @param mixed $description
     * @param null $exception
     * 
     * @return [type]
     */
    public function createFailedTicketHistory($ticketId, $userId, $description, $exception = null)
    {
        return FailedTicketHistory::create([
            'user_id' => $userId,
            'ticket_id' => $ticketId,
            'description' => $description,
            'exceptions' => $exception
        ]);
    }
}
