<?php

namespace BitApps\PiPro\src\Integrations\Apify;

use BitApps\PiPro\Deps\BitApps\WPKit\Helpers\JSON;

if (!\defined('ABSPATH')) {
    exit;
}

class ApifyService
{
    private $http;

    private $baseUrl;

    /**
     * ApifyService constructor.
     *
     * @param mixed $httpClient
     */
    public function __construct($httpClient)
    {
        $this->http = $httpClient;
        $this->baseUrl = 'https://api.apify.com/v2';
    }

    /**
     * Run an Apify actor.
     *
     * @param string $actorId
     * @param array  $data
     *
     * @return array
     */
    public function runActor($actorId, $data)
    {
        $baseUrl = $this->baseUrl . "/acts/{$actorId}/runs";

        if ($data['run-synchronously'] === true) {
            $baseUrl = $this->baseUrl . "/acts/{$actorId}/run-sync";
        }

        $queryParams = [
            'memory'  => $data['memory'] ?? null,
            'build'   => $data['build'] ?? null,
            'timeout' => $data['timeout'] ?? null
        ];

        $queryParams = array_filter($queryParams);
        $endPoint = add_query_arg($queryParams, $baseUrl);
        $response = $this->http->request($endPoint, 'POST', []);

        return [
            'response'    => $response ?: ['success' => true],
            'payload'     => $actorId,
            'status_code' => $this->http->getResponseCode()
        ];
    }

    /**
     * Get the last run of an actor.
     *
     * @param string $actorId
     * @param array  $data
     *
     * @return array
     */
    public function getLastActor($actorId, $data)
    {
        $baseUrl = $this->baseUrl . "/acts/{$actorId}/runs/last";
        $endPoint = add_query_arg($data, $baseUrl);
        $response = $this->http->request($endPoint, 'GET', []);

        return [
            'response'    => $response,
            'payload'     => $actorId,
            'status_code' => $this->http->getResponseCode()
        ];
    }

    /**
     * Get the last run of an actor task.
     *
     * @param string $taskId
     * @param array  $data
     *
     * @return array
     */
    public function getLastTask($taskId, $data)
    {
        $baseUrl = $this->baseUrl . "/actor-tasks/{$taskId}/runs/last";
        $endPoint = add_query_arg($data, $baseUrl);
        $response = $this->http->request($endPoint, 'GET', []);

        return [
            'response'    => $response,
            'payload'     => $taskId,
            'status_code' => $this->http->getResponseCode()
        ];
    }

    /**
     * Get runs of an actor with pagination and sorting options.
     *
     * @param string $actorId
     * @param array  $data
     *
     * @return array
     */
    public function getRuns($actorId, $data)
    {
        $baseUrl = $this->baseUrl . "/acts/{$actorId}/runs";
        $queryParams = [
            'limit'  => $data['limit'] ?? null,
            'offset' => $data['offset'] ?? null,
            'desc'   => $data['desc'] ?? false
        ];

        $queryParams = array_filter($queryParams);

        $endPoint = add_query_arg($queryParams, $baseUrl);
        $response = $this->http->request($endPoint, 'GET', []);

        return [
            'response'    => $response,
            'payload'     => $actorId,
            'status_code' => $this->http->getResponseCode()
        ];
    }

    /**
     * Get list of user's actor runs with pagination and sorting options.
     *
     * @param array $data
     *
     * @return array
     */
    public function getUserRunsList($data)
    {
        $baseUrl = $this->baseUrl . '/actor-runs';
        $queryParams = [
            'limit'  => $data['limit'] ?? null,
            'offset' => $data['offset'] ?? null,
            'desc'   => $data['desc'] ?? false,
            'status' => $data['status'] ?? null
        ];

        $queryParams = array_filter($queryParams);
        $endPoint = add_query_arg($queryParams, $baseUrl);
        $response = $this->http->request($endPoint, 'GET', []);

        return [
            'response'    => $response,
            'payload'     => $queryParams,
            'status_code' => $this->http->getResponseCode()
        ];
    }

    /**
     * Run an Apify actor task.
     *
     * @param string $taskId
     * @param array  $data
     *
     * @return array
     */
    public function runTask($taskId, $data)
    {
        $baseUrl = $this->baseUrl . "/actor-tasks/{$taskId}/runs";

        if ($data['run-synchronously'] === true) {
            $baseUrl = $this->baseUrl . "/actor-tasks/{$taskId}/run-sync";
        }

        $queryParams = [
            'memory'  => $data['memory'] ?? null,
            'build'   => $data['build'] ?? null,
            'timeout' => $data['timeout'] ?? null
        ];

        $queryParams = array_filter($queryParams);
        $endPoint = add_query_arg($queryParams, $baseUrl);
        $response = $this->http->request($endPoint, 'POST', []);

        return [
            'response'    => $response ?: ['success' => true],
            'payload'     => $taskId,
            'status_code' => $this->http->getResponseCode()
        ];
    }

    /**
     * Get items from an Apify dataset.
     *
     * @param string $datasetId
     * @param array  $data
     *
     * @return array Response with dataset items, payload, and status code
     */
    public function getDatasetItems($datasetId, $data = null)
    {
        $baseUrl = $this->baseUrl . "/datasets/{$datasetId}/items";

        $queryParams = [
            'limit'  => $data['limit'] ?? null,
            'offset' => $data['offset'] ?? null,
            'clean'  => $data['clean'] ?? false
        ];

        $queryParams = array_filter($queryParams);
        $endPoint = add_query_arg($queryParams, $baseUrl);
        $response = $this->http->request($endPoint, 'GET', []);

        return [
            'response'    => $response,
            'payload'     => $datasetId,
            'status_code' => $this->http->getResponseCode()
        ];
    }

    /**
     * Create or update a record in a key-value store.
     *
     * @param string $storeId
     * @param string $key
     * @param mixed  $data
     *
     * @return array
     */
    public function createKeyValueRecord($storeId, $key, $data)
    {
        $baseUrl = $this->baseUrl . "/key-value-stores/{$storeId}/records/{$key}";
        $recordData = JSON::encode($data);
        $response = $this->http->request($baseUrl, 'PUT', $recordData);

        return [
            'response'    => $response,
            'payload'     => ['storeId' => $storeId, 'key' => $key],
            'status_code' => $this->http->getResponseCode()
        ];
    }

    /**
     * Scrape a single URL using Apify's built-in scraper.
     *
     * @param array $data
     *
     * @return array
     */
    public function scrapeSingleUrl($data)
    {
        $endPoint = $this->baseUrl . '/acts/apify~website-content-crawler/run-sync-get-dataset-items';

        $data = array_merge(
            $data,
            [
                'startUrls'           => [['url' => $data['url']]],
                'maxRequestsPerCrawl' => 10,
                'proxyConfiguration'  => ['useApifyProxy' => true],

                'requestTimeoutSecs'  => 60,
                'pageLoadTimeoutSecs' => 60,
                'maxCrawlingDepth'    => 1,
            ]
        );


        $queryParams = [
            'timeout' => $data['timeout'] ?? 300
        ];

        $endPointWithTimeout = add_query_arg($queryParams, $endPoint);

        unset($data['url']);
        $urlData = JSON::encode($data);
        $response = $this->http->request($endPointWithTimeout, 'POST', $urlData);

        return [
            'response'    => $response,
            'payload'     => $urlData,
            'status_code' => $this->http->getResponseCode()
        ];
    }

    /**
     * Get a record from a key-value store.
     *
     * @param string $storeId
     * @param string $key
     *
     * @return array
     */
    public function getKeyValueRecord($storeId, $key)
    {
        $endPoint = $this->baseUrl . "/key-value-stores/{$storeId}/records/{$key}";
        $response = $this->http->request($endPoint, 'GET', []);

        return [
            'response'    => $response,
            'payload'     => ['storeId' => $storeId, 'key' => $key],
            'status_code' => $this->http->getResponseCode()
        ];
    }
}
