<?php

namespace BitApps\SocialPro\HTTP\Services\Social\ThreadsService;

use AllowDynamicProperties;
use BitApps\Social\HTTP\Services\Interfaces\SocialInterface;
use BitApps\Social\HTTP\Services\Traits\LoggerTrait;
use BitApps\Social\Model\Schedule;
use BitApps\Social\Utils\Common;
use BitApps\SocialPro\Deps\BitApps\WPKit\Http\Client\HttpClient;

#[AllowDynamicProperties]
class PostPublishThreadsService implements SocialInterface
{
    use Common, LoggerTrait;

    public $baseUrl = 'https://graph.threads.net/v1.0/';

    public $userName;

    private $postUrl = 'https://www.threads.com';

    private $httpClient;

    private $accessToken;

    private $mediaUploadErrors = [];

    private $commentError = [];

    private $accountId;

    public function __construct()
    {
        $this->httpClient = new HttpClient();
    }

    public function publishPost($data)
    {
        $post = $data['post'] ?? null;
        $template = (object) $data['template'];
        $scheduleType = $data['schedule_type'] ?? null;
        $accountDetails = $data['account_details'];
        $schedule_id = $data['schedule_id'] ?? null;
        $accountId = $accountDetails->account_id;
        $accountName = $accountDetails->account_name;

        $tokenService = new ThreadsRefreshTokenService($accountDetails);

        $this->accessToken = $tokenService->accessToken();
        $this->accountId = $accountDetails->account_id;

        $postData = $this->postData($scheduleType, $post, $template);

        $response = $this->createPost($postData);

        if (\array_key_exists('keepLogs', $data) && !$data['keepLogs']) {
            return;
        }

        if (isset($response->shortcode)) {
            $postUrl = "{$this->postUrl}/post/{$response->shortcode}";
        }

        $responseData = [
            'schedule_id' => $schedule_id,
            'details'     => [
                'account_id'   => $accountId,
                'account_name' => $accountName,
                'post_id'      => $post['ID'] ?? null,
                'response'     => $response,
                'post_url'     => $postUrl ?? null,
            ],
            'platform' => 'threads',
            'status'   => \is_object($response) && property_exists($response, 'id') ? 1 : 0
        ];

        if (\count($this->mediaUploadErrors)) {
            $responseData['details']['imageUploadErrors'] = $this->mediaUploadErrors;
        }
        if (\count($this->commentError)) {
            $responseData['details']['commentError'] = $this->commentError;
        }

        $this->logCreate($responseData);
    }

    public function postData($scheduleType, $post, $template)
    {
        $postData = [];
        $template = (object) $template;

        if ($scheduleType === Schedule::scheduleType['DIRECT_SHARE']) {
            $templateMedia = array_map(function ($item) {
                return $item['url'];
            }, $template->media);

            $postData['content'] = $template->content ?? null;
            $postData['media'] = $template->isAllImages ? $templateMedia : null;
            $postData['link'] = $template->isLinkCard ? $template->link : null;
            $postData['topic'] = $template->topic ?? null;
            $postData['comment'] = $template->comment ?? null;
        } else {
            $template->platform = 'threads';
            $postData = $this->replacePostContent($post['ID'], $template);

            if (!empty($postData['featureImage'])) {
                $postData['media'] = [$postData['featureImage']];
            }
            if (!empty($postData['allImages'])) {
                $postData['media'] = $postData['allImages'];
            }
            if (!empty($template->topic)) {
                $postData['topic'] = $this->replaceTagValue($template->topic, (object) $post);
            }
        }

        return $postData;
    }

    private function shortCode($creationId)
    {
        $postPublishUrl = "{$this->baseUrl}/{$creationId}?";
        $params['fields'] = 'shortcode';
        $params['access_token'] = $this->accessToken;

        $publishPostUrlWithParams = $postPublishUrl . http_build_query($params);

        return $this->httpClient->request($publishPostUrlWithParams, 'GET', []);
    }

    private function createPost($postData)
    {
        $creationResponse = $this->creationId($postData);

        if (isset($creationResponse->error)) {
            return $creationResponse->error;
        }

        $post = $this->threadsPublishPost($creationResponse->id);

        if (isset($post->error)) {
            return $post->error;
        }

        if (!empty($postData['comment'])) {
            $commentResponse = $this->createReplies($post->id, $postData['comment']);

            if (isset($commentResponse->error)) {
                $this->commentError[] = $commentResponse->error;
            }

            if (isset($commentResponse->id)) {
                $this->threadsPublishPost($commentResponse->id);
            }
        }

        return $this->shortCode($post->id);
    }

    private function carouselItemIds($postData)
    {
        $mediaIds = [];
        foreach ($postData['media'] as $mediaUrl) {
            $mediaId = $this->createCarouselContainer($mediaUrl);
            if ($mediaId) {
                $mediaIds[] = $mediaId;
            }
        }

        return $mediaIds;
    }

    private function createCarouselContainer($mediaUrl)
    {
        $containerPostUrl = "{$this->baseUrl}{$this->accountId}/threads?";

        $params = [
            'is_carousel_item' => true,
            'media_type'       => 'IMAGE',
            'image_url'        => $mediaUrl,
            'access_token'     => $this->accessToken];

        $postUrlWithParams = $containerPostUrl . http_build_query($params);
        $response = $this->httpClient->request($postUrlWithParams, 'POST', []);
        if (isset($response->error)) {
            $this->mediaUploadErrors[] = $response->error;

            return;
        }

        return $response->id;
    }

    private function creationId($postData)
    {
        $postUrl = "{$this->baseUrl}{$this->accountId}/threads?";

        if (!empty($postData['content']) && empty($postData['media'])) {
            $params['media_type'] = 'TEXT';
        }

        if (!empty($postData['media']) && \count($postData['media']) === 1) {
            $params['media_type'] = 'IMAGE';
            $params['image_url'] = $postData['media'][0];
        }

        if (!empty($postData['media']) && \count($postData['media']) > 1) {
            $params['media_type'] = 'CAROUSEL';
            $params['children'] = $this->carouselItemIds($postData);
        }

        if (!empty($postData['content'])) {
            $params['text'] = $postData['content'];
        }

        if (!empty($postData['topic'])) {
            $params['topic_tag'] = $postData['topic'];
        }

        if (!empty($postData['link'])) {
            $params['link_attachment'] = $postData['link'];
        }

        $params['access_token'] = $this->accessToken;

        $postUrlWithParams = $postUrl . http_build_query($params);

        return $this->httpClient->request($postUrlWithParams, 'POST', []);
    }

    private function threadsPublishPost($id)
    {
        $publishUrl = "{$this->baseUrl}/{$this->accountId}/threads_publish?";

        $publishParams = [
            'creation_id'  => $id,
            'access_token' => $this->accessToken,
        ];

        $publishPostUrlWithParams = $publishUrl . http_build_query($publishParams);

        return $this->httpClient->request($publishPostUrlWithParams, 'POST', []);
    }

    private function createReplies($threadsId, $replyText)
    {
        $replyUrl = "{$this->baseUrl}/me/threads?";

        $params = [
            'media_type'   => 'TEXT',
            'text'         => $replyText,
            'reply_to_id'  => $threadsId,
            'access_token' => $this->accessToken,
        ];

        $replyUrlWithParams = $replyUrl . http_build_query($params);

        return $this->httpClient->request($replyUrlWithParams, 'POST', []);
    }
}
