<?php

namespace BitApps\PiPro\src\Integrations\Newsletter;

use BitApps\Pi\Config;
use BitApps\Pi\Helpers\MixInputHandler;
use BitApps\Pi\src\Authorization\AuthorizationFactory;
use BitApps\Pi\src\Authorization\AuthorizationType;
use BitApps\Pi\src\Flow\NodeInfoProvider;
use BitApps\PiPro\Deps\BitApps\WPKit\Http\Client\HttpClient;
use BitApps\PiPro\Deps\BitApps\WPValidator\Validator;

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


final class NewsletterServices
{
    private NodeInfoProvider $nodeInfoProvider;

    private HttpClient $httpClient;

    public function __construct(NodeInfoProvider $nodeInfoProvider)
    {
        $this->nodeInfoProvider = $nodeInfoProvider;
        $this->httpClient = $this->initializeHttpClient();
    }

    /**
     * Create Subscriptions.
     *
     * @return array
     */
    public function createSubscriptions()
    {
        $optIn = $this->nodeInfoProvider->getFieldMapConfigs('opt-in.value');

        $fieldMappings = $this->prepareSubscriberFieldMappings();

        $fieldMappings['opt_in'] = $optIn ? 'double' : 'single';

        $this->httpClient->setBody($fieldMappings);

        $response = $this->httpClient->post('subscriptions');

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

    /**
     * Create Subscriber.
     *
     * @return array
     */
    public function createSubscriber()
    {
        $fieldMappings = $this->prepareSubscriberFieldMappings();

        $this->httpClient->setBody($fieldMappings);

        $response = $this->httpClient->post('subscribers');

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

    /**
     * Update Subscriber.
     *
     * @return array
     */
    public function updateSubscriber()
    {
        $id = MixInputHandler::replaceMixTagValue($this->nodeInfoProvider->getFieldMapConfigs('id.value'));

        $rules = [
            'id' => ['required', 'integer'],
        ];

        $errors = self::validateFieldMap(['id' => $id], $rules);

        if ($errors) {
            return $errors;
        }

        $fieldMappings = $this->prepareSubscriberFieldMappings();

        $this->httpClient->setBody($fieldMappings);

        $response = $this->httpClient->put('subscribers/' . $id);

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

    /**
     * Get Subscribers.
     *
     * @return array
     */
    public function getAllSubscriber()
    {
        return $this->fetchAllData('subscribers');
    }

    /**
     * Get Subscriber by Email.
     *
     * @return array
     */
    public function getSubscriberByEmail()
    {
        $fieldMappings = $this->nodeInfoProvider->getFieldMapData();

        $rules = [
            'email' => ['required', 'sanitize:email'],
        ];

        $errors = self::validateFieldMap($fieldMappings, $rules);

        if ($errors) {
            return $errors;
        }

        $response = $this->httpClient->get('subscribers/' . $fieldMappings['email']);

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

    /**
     * Get Subscriber by ID.
     *
     * @return array
     */
    public function getSubscriberById()
    {
        return $this->getDataById('subscribers');
    }

    /**
     * Delete Subscriber by ID.
     *
     * @return array
     */
    public function deleteSubscriberById()
    {
        $fieldMappings = $this->nodeInfoProvider->getFieldMapData();

        $rules = [
            'id' => ['required', 'integer'],
        ];

        $errors = self::validateFieldMap($fieldMappings, $rules);

        if ($errors) {
            return $errors;
        }

        $response = $this->httpClient->delete('subscribers/' . $fieldMappings['id']);

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

    /**
     * Delete Subscriber by email.
     *
     * @return array
     */
    public function deleteSubscriberByEmail()
    {
        $fieldMappings = $this->nodeInfoProvider->getFieldMapData();

        $rules = [
            'email' => ['required', 'sanitize:email'],
        ];

        $errors = self::validateFieldMap($fieldMappings, $rules);

        if ($errors) {
            return $errors;
        }

        $response = $this->httpClient->delete('subscribers/' . $fieldMappings['email']);

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

    /**
     * Get Subscribers.
     *
     * @return array
     */
    public function getAllNewsletter()
    {
        return $this->fetchAllData('newsletters');
    }

    /**
     * Get Newsletter by ID.
     *
     * @return array
     */
    public function getNewsletterById()
    {
        return $this->getDataById('newsletters');
    }

    /**
     * Get Lists.
     *
     * @return array
     */
    public function getAllList()
    {
        return $this->fetchAllData('lists');
    }

    /**
     * Get List by ID.
     *
     * @return array
     */
    public function getListById()
    {
        return $this->getDataById('lists');
    }

    /**
     * Validate field map.
     *
     * @param array $fieldMappings
     * @param array $validationRules
     * @param null|array $payload
     *
     * @return null|array
     */
    public static function validateFieldMap($fieldMappings, $validationRules, $payload = null)
    {
        $validator = new Validator();
        $validation = $validator->make($fieldMappings, $validationRules);

        if ($validation->fails()) {
            return [
                'response'    => $validation->errors(),
                'payload'     => $payload ?? $fieldMappings,
                'status_code' => 400
            ];
        }
    }

    private function getDataById($endpoint)
    {
        $fieldMappings = $this->nodeInfoProvider->getFieldMapData();

        $rules = [
            'id' => ['required', 'integer'],
        ];

        $errors = self::validateFieldMap($fieldMappings, $rules);

        if ($errors) {
            return $errors;
        }

        $response = $this->httpClient->get($endpoint . '/' . $fieldMappings['id']);

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

    /**
     * Fetch all data from the given endpoint with pagination support.
     *
     * @param string $endpoint
     *
     * @return array
     */
    private function fetchAllData($endpoint)
    {
        $fieldMappings = $this->nodeInfoProvider->getFieldMapData();

        $this->setQueryParams(
            [
                'per_page' => $fieldMappings['per_page'] ?? 100,
                'page'     => $fieldMappings['page'] ?? 1,
            ]
        );

        $response = $this->httpClient->get($endpoint);

        return [
            'response'    => ['data' => $response],
            'payload'     => $fieldMappings,
            'status_code' => $this->httpClient->getResponseCode()
        ];
    }

    /**
     * Set query parameters for the HTTP client.
     */
    private function setQueryParams(array $params)
    {
        $this->httpClient->setQueryParams($params);
    }

    /**
     * Initialize HttpClient with authorization and base URL.
     *
     * @return HttpClient
     */
    private function initializeHttpClient()
    {
        $connectionId = $this->nodeInfoProvider->getFieldMapConfigs('connection-id.value');

        $authHandler = AuthorizationFactory::getAuthorizationHandler(
            AuthorizationType::BASIC_AUTH,
            $connectionId
        );

        $accessToken = $authHandler->getAccessToken();

        $wpApiURL = Config::get('WP_API_URL');
        $baseUrl = $wpApiURL['base'] . 'newsletter/v2/';

        return new HttpClient(
            [
                'base_uri' => $baseUrl,
                'headers'  => [
                    'Authorization' => $accessToken,
                    'Content-Type'  => 'application/json',
                ],
            ]
        );
    }

    /**
     * Prepare subscriber field mappings.
     *
     * @return array
     */
    private function prepareSubscriberFieldMappings()
    {
        $fieldMappings = $this->nodeInfoProvider->getFieldMapRepeaters('field-map.value', false, true, 'newsletterField');
        $customFields = $this->nodeInfoProvider->getFieldMapRepeaters('custom-field-map.value', false, true, 'newsletterCustomField');
        $data = $this->nodeInfoProvider->getFieldMapData();

        $data['lists'] = array_map(
            function ($listId) {
                return [
                    'id'    => $listId,
                    'value' => true,
                ];
            },
            $data['lists'] ?? []
        );

        $fieldMappings['extra_fields'] = array_map(
            function ($id, $value) {
                return [
                    'id'    => $id,
                    'value' => $value,
                ];
            },
            array_keys($customFields),
            $customFields
        );

        return array_merge($fieldMappings, $data);
    }
}
