<?php
declare(strict_types=1);

namespace WriteTextAI\WriteTextAI\Helper;

use Magento\Framework\App\Helper\AbstractHelper;
use Magento\Framework\App\Helper\Context;
use Magento\Integration\Model\IntegrationFactory;
use Magento\Integration\Model\OauthService;
use Magento\Integration\Model\AuthorizationService;
use Magento\Integration\Model\ResourceModel\Integration\Collection as IntegrationCollection;
use Magento\Framework\Exception\LocalizedException;
use Psr\Log\LoggerInterface;
use Magento\Integration\Model\ResourceModel\Oauth\Consumer\Collection as ConsumerCollection;
use Magento\Framework\Encryption\EncryptorInterface;

/**
 * Class IntegrationTokenHelper
 * Helper for generating and managing Magento integration tokens programmatically
 */
class IntegrationTokenHelper extends AbstractHelper
{
    /**
     * const integration name
     */
    public const INTEGRATION_NAME = 'writetextai_integration';

    /**
     * const integration email
     */
    public const INTEGRATION_EMAIL = 'integration@writetext.ai';

    /**
     * @var IntegrationFactory
     */
    private $integrationFactory;

    /**
     * @var OauthService
     */
    private $oauthService;

    /**
     * @var AuthorizationService
     */
    private $authorizationService;

    /**
     * @var IntegrationCollection
     */
    private $integrationCollection;

    /**
     * @var ConsumerCollection
     */
    private $consumerCollection;

    /**
     * @var LoggerInterface
     */
    private $logger;

    /**
     * @var EncryptorInterface
     */
    private $encryptor;

    /**
     * @param Context $context
     * @param IntegrationFactory $integrationFactory
     * @param OauthService $oauthService
     * @param AuthorizationService $authorizationService
     * @param IntegrationCollection $integrationCollection
     * @param ConsumerCollection $consumerCollection
     * @param LoggerInterface $logger
     * @param EncryptorInterface $encryptor
     */
    public function __construct(
        Context $context,
        IntegrationFactory $integrationFactory,
        OauthService $oauthService,
        AuthorizationService $authorizationService,
        IntegrationCollection $integrationCollection,
        ConsumerCollection $consumerCollection,
        LoggerInterface $logger,
        EncryptorInterface $encryptor
    ) {
        parent::__construct($context);
        $this->integrationFactory = $integrationFactory;
        $this->oauthService = $oauthService;
        $this->authorizationService = $authorizationService;
        $this->integrationCollection = $integrationCollection;
        $this->consumerCollection = $consumerCollection;
        $this->logger = $logger;
        $this->encryptor = $encryptor;
    }

    /**
     * Create a new integration with access to WriteTextAI API
     *
     * @param string $name Integration name
     * @param string $email Integration email
     * @param string $endpoint Integration endpoint URL (optional)
     * @return array Integration data with access token
     * @throws LocalizedException
     */
    public function createIntegration(
        string $name = self::INTEGRATION_NAME,
        string $email = self::INTEGRATION_EMAIL,
        string $endpoint = ''
    ): array {
        try {
            // Check if integration already exists
            $existingIntegration = $this->getIntegrationByName();
            if ($existingIntegration) {
                throw new LocalizedException(__('Integration with name "%1" already exists', $name));
            }

            // Create integration
            $integration = $this->integrationFactory->create();
            $integration->setData([
                'name' => $name,
                'email' => $email ?: $name . '@example.com',
                'endpoint' => $endpoint,
                'status' => 1, // Active
                'setup_type' => 0, // Manual
            ]);
            $integration->save();

            // Create OAuth consumer
            $consumer = $this->oauthService->createConsumer(['name' => $name]);
            $integration->setConsumerId($consumer->getId());
            $integration->save();

            // Authorize the integration with comprehensive permissions
            $this->authorizationService->grantPermissions(
                $integration->getId(),
                [
                    // WriteTextAI permissions - all available resources
                    'WriteTextAI_WriteTextAI::api_transfer',
                ]
            );

            // Generate access token after authorization
            $accessToken = $this->oauthService->createAccessToken($consumer->getId(), true);
            //get access token
            $accessToken = $this->oauthService->getAccessToken($consumer->getId());
            
            $this->logger->info('Integration created successfully', [
                'integration_name' => $name,
                'integration_id' => $integration->getData(),
                'consumer_id' => $consumer->getId()
            ]);

            return [
                'integration_id' => $integration->getId(),
                'name' => $name,
                'consumer_key' => $consumer->getKey(),
                'consumer_secret' => $consumer->getSecret(),
                'access_token' => $accessToken->getToken(),
                'access_token_secret' => $accessToken->getSecret(),
                'created_at' => date('Y-m-d H:i:s'),
                'status' => 'active'
            ];
        } catch (\Exception $e) {
            $this->logger->error('Failed to create integration', [
                'integration_name' => $name,
                'error' => $e->getMessage()
            ]);
            throw new LocalizedException(__('Failed to create integration: %1', $e->getMessage()));
        }
    }

    /**
     * Get integration by name
     *
     * @return \Magento\Integration\Model\Integration|null
     */
    public function getIntegrationByName(): ?\Magento\Integration\Model\Integration
    {
        $collection = clone $this->integrationCollection;
        $collection->addFieldToFilter('name', self::INTEGRATION_NAME);
        $integration = $collection->getFirstItem();
        
        return $integration->getId() ? $integration : null;
    }

    /**
     * Get access token for an existing integration
     *
     * @param string $integrationName
     * @return string|null
     * @throws LocalizedException
     */
    public function getAccessToken(string $integrationName): ?string
    {
        $integration = $this->getIntegrationByName();
        if (!$integration) {
            throw new LocalizedException(__('Integration "%1" not found', $integrationName));
        }

        $consumerId = $integration->getConsumerId();
        if (!$consumerId) {
            throw new LocalizedException(__('No consumer found for integration "%1"', $integrationName));
        }

        try {
            $accessToken = $this->oauthService->getAccessToken($consumerId);
            return $accessToken ? $accessToken->getToken() : null;
        } catch (\Exception $e) {
            $this->logger->error('Failed to get access token', [
                'integration_name' => $integrationName,
                'consumer_id' => $consumerId,
                'error' => $e->getMessage()
            ]);
            return null;
        }
    }

    /**
     * Regenerate access token for an existing integration
     *
     * @param string $integrationName
     * @return string New access token
     * @throws LocalizedException
     */
    public function regenerateAccessToken(string $integrationName): string
    {
        $integration = $this->getIntegrationByName();
        if (!$integration) {
            throw new LocalizedException(__('Integration "%1" not found', $integrationName));
        }

        $consumerId = $integration->getConsumerId();
        if (!$consumerId) {
            throw new LocalizedException(__('No consumer found for integration "%1"', $integrationName));
        }

        try {
            // Revoke existing token
            $this->oauthService->deleteIntegrationToken($consumerId);
            
            // Create new token
            $accessToken = $this->oauthService->createAccessToken($consumerId, true);
            
            if (!$accessToken || !is_object($accessToken)) {
                throw new LocalizedException(
                    __('Failed to create new access token for integration "%1"', $integrationName)
                );
            }
            
            $this->logger->info('Access token regenerated', [
                'integration_name' => $integrationName,
                'consumer_id' => $consumerId
            ]);

            return $accessToken->getToken();
        } catch (\Exception $e) {
            $this->logger->error('Failed to regenerate access token', [
                'integration_name' => $integrationName,
                'consumer_id' => $consumerId,
                'error' => $e->getMessage()
            ]);
            throw new LocalizedException(__('Failed to regenerate access token: %1', $e->getMessage()));
        }
    }

    /**
     * Delete an integration
     *
     * @param string $integrationName
     * @return bool
     * @throws LocalizedException
     */
    public function deleteIntegration(string $integrationName): bool
    {
        $integration = $this->getIntegrationByName();
        if (!$integration) {
            throw new LocalizedException(__('Integration "%1" not found', $integrationName));
        }

        try {
            // Delete OAuth tokens and consumer
            if ($integration->getConsumerId()) {
                $this->oauthService->deleteIntegrationToken($integration->getConsumerId());
            }

            // Delete integration
            $integration->delete();

            $this->logger->info('Integration deleted', [
                'integration_name' => $integrationName,
                'integration_id' => $integration->getId()
            ]);

            return true;
        } catch (\Exception $e) {
            $this->logger->error('Failed to delete integration', [
                'integration_name' => $integrationName,
                'error' => $e->getMessage()
            ]);
            throw new LocalizedException(__('Failed to delete integration: %1', $e->getMessage()));
        }
    }

    /**
     * List all WriteTextAI integrations
     *
     * @return array
     */
    public function listIntegrations(): array
    {
        $collection = clone $this->integrationCollection;
        $integrations = [];

        foreach ($collection as $integration) {
            $accessToken = null;
            try {
                $accessToken = $this->getAccessToken($integration->getName());
            } catch (\Exception $e) {
                // Token might not exist, continue
            }

            $integrations[] = [
                'id' => $integration->getId(),
                'name' => $integration->getName(),
                'email' => $integration->getEmail(),
                'status' => $integration->getStatus() ? 'active' : 'inactive',
                'created_at' => $integration->getCreatedAt(),
                'updated_at' => $integration->getUpdatedAt(),
                'has_token' => !empty($accessToken)
            ];
        }

        return $integrations;
    }

    /**
     * Get integration by name
     *
     * @return array|null
     */
    public function getIntegrationData(): ?array
    {
        $name = self::INTEGRATION_NAME;
        $integration = $this->getIntegrationByName();
        if (!$integration) {
            //delete integration
            $integration = $this->createIntegration($name);
            return $integration;
        }

        // Get consumer
        $consumer = $this->consumerCollection->addFieldToFilter('entity_id', $integration->getConsumerId())
            ->getFirstItem();
        if (!$consumer) {
            throw new LocalizedException(__('Consumer not found for integration "%1"', $name));
        }

        // Get access token
        $accessToken = $this->oauthService->getAccessToken($consumer->getId());
        if (!$accessToken) {
            throw new LocalizedException(__('Access token not found for integration "%1"', $name));
        }

        if ($integration->getStatus() == 0) {
            //delete integration
            $this->deleteIntegration($name);
            $integration = $this->createIntegration($name);
            return $integration;
        }
        return [
            'integration_id' => $integration->getId(),
            'name' => $name,
            'consumer_key' => $consumer->getKey(),
            'consumer_secret' => $this->encryptor->decrypt($consumer->getSecret()),
            'access_token' => $accessToken->getToken(),
            'access_token_secret' => $accessToken->getSecret(),
            'status' => $integration->getStatus() ? 'active' : 'inactive'
        ];
    }
}
