<?php
/**
 * 2026 Paysera
 *
 * NOTICE OF LICENSE
 *
 * This source file is subject to the Academic Free License (AFL 3.0)
 * that is bundled with this package in the file LICENSE.txt.
 * It is also available through the world-wide-web at this URL:
 * http://opensource.org/licenses/afl-3.0.php
 * If you did not receive a copy of the license and are unable to
 * obtain it through the world-wide-web, please send an email
 * to license@prestashop.com so we can send you a copy immediately.
 *
 * @author Paysera <plugins@paysera.com>
 * @copyright 2026 Paysera
 * @license http://opensource.org/licenses/afl-3.0.php Academic Free License (AFL 3.0)
 * International Registered Trademark & Property of Paysera
 */

declare(strict_types=1);

use Paysera\PrestashopPayments\Checker\ModuleStatusChecker;
use Paysera\PrestashopPayments\Controller\AbstractPayseraAdminController;
use Paysera\PrestashopPayments\Diagnostic\Service\Generator\DiagnosticReportGenerator;
use Paysera\PrestashopPayments\Diagnostic\Service\Manager\DiagnosticManager;
use Paysera\PrestashopPayments\Provider\SettingsProvider;
use Paysera\PrestashopPayments\Service\AuthorizationService;
use Paysera\PrestashopPayments\Service\CmsToolsFacade;
use Paysera\PrestashopPayments\Service\Payment\PaymentSettingsService;
use Paysera\PrestashopPayments\Service\Payment\PaymentsListService;
use Paysera\PrestashopPayments\Service\Payment\PaymentStatusPollingService;
use Symfony\Component\HttpFoundation\Request;

if (!defined('_PS_VERSION_')) {
    exit;
}

class AdminPayseraPaymentsAjaxController extends AbstractPayseraAdminController
{
    private AuthorizationService $authorizationService;
    private SettingsProvider $settingsProvider;
    private ModuleStatusChecker $moduleStatusChecker;
    private PaymentSettingsService $paymentSettingsService;
    private PaymentsListService $paymentsListService;
    private PaymentStatusPollingService $paymentStatusPollingService;
    private CmsToolsFacade $cmsToolsFacade;
    private DiagnosticManager $diagnosticManager;
    private DiagnosticReportGenerator $diagnosticReportGenerator;

    public function __construct()
    {
        parent::__construct();

        $this->authorizationService = $this->module->get(AuthorizationService::class);
        $this->settingsProvider = $this->module->get(SettingsProvider::class);
        $this->moduleStatusChecker = $this->module->get(ModuleStatusChecker::class);
        $this->paymentSettingsService = $this->module->get(PaymentSettingsService::class);
        $this->paymentsListService = $this->module->get(PaymentsListService::class);
        $this->paymentStatusPollingService = $this->module->get(PaymentStatusPollingService::class);
        $this->cmsToolsFacade = $this->module->get(CmsToolsFacade::class);
        $this->diagnosticManager = $this->module->get(DiagnosticManager::class);
        $this->diagnosticReportGenerator = $this->module->get(DiagnosticReportGenerator::class);
    }

    public function postProcess()
    {
        if ($this->ajax && !$this->checkToken()) {
            $this->ajaxErrorResponse('Invalid security token', 403);

            return;
        }

        return parent::postProcess();
    }

    public function ajaxProcessToggleSandbox(): void
    {
        if (!$this->isPostRequest()) {
            $this->ajaxErrorResponse('Method not allowed', 405);

            return;
        }

        $newMode = $this->settingsProvider->toggleSandboxMode();

        $this->ajaxSuccessResponse(['sandbox_mode' => $newMode]);
    }

    public function ajaxProcessGetConnectionStatus(): void
    {
        $status = $this->moduleStatusChecker->getConnectionStatus($this->module);

        $this->ajaxSuccessResponse(['connection_status' => $status]);
    }

    public function ajaxProcessAuthorize(): void
    {
        if (!$this->isPostRequest()) {
            $this->ajaxErrorResponse('Method not allowed', 405);

            return;
        }

        $data = $this->getJsonInput();

        if ($data === null) {
            $this->ajaxErrorResponse($this->trans('Invalid request body', [], 'Modules.Payserapayments.Global'), 400);

            return;
        }

        $clientId = trim((string) ($data['clientId'] ?? ''));
        $clientSecret = trim((string) ($data['clientSecret'] ?? ''));

        if ($clientId === '') {
            $this->ajaxErrorResponse($this->trans('Client ID cannot be empty', [], 'Modules.Payserapayments.Global'), 422);

            return;
        }

        if ($clientSecret === '') {
            $this->ajaxErrorResponse($this->trans('Client secret cannot be empty', [], 'Modules.Payserapayments.Global'), 422);

            return;
        }

        $success = $this->authorizationService->authorize($clientId, $clientSecret);

        $this->ajaxSuccessResponse([
            'success' => $success,
            'message' => $success
                ? $this->trans('Your Paysera account is connected. You can now configure payment settings.', [], 'Modules.Payserapayments.Global')
                : $this->trans('Invalid Client ID or Secret. Please check your credentials and try again.', [], 'Modules.Payserapayments.Global'),
        ]);
    }

    public function ajaxProcessGetCredentials(): void
    {
        $credentials = $this->authorizationService->getStoredCredentials();

        if ($credentials === null) {
            $this->ajaxSuccessResponse([
                'success' => false,
                'credentials' => null,
            ]);

            return;
        }

        $this->ajaxSuccessResponse([
            'success' => true,
            'credentials' => [
                'clientId' => $credentials->getClientId(),
                'clientSecret' => $credentials->getClientSecret(),
            ],
        ]);
    }

    public function ajaxProcessUpdatePaymentSettings(): void
    {
        if (!$this->isPostRequest()) {
            $this->ajaxErrorResponse('Method not allowed', 405);

            return;
        }

        $data = $this->getJsonInput();

        if ($data === null) {
            $this->ajaxErrorResponse($this->trans('Invalid request body', [], 'Modules.Payserapayments.Global'), 400);

            return;
        }

        $result = $this->paymentSettingsService->updatePaymentSettings($data);

        if (!$result['success']) {
            $this->ajaxErrorResponse(implode(' ', $result['errors']), 422);

            return;
        }

        $this->ajaxSuccessResponse($result['data']);
    }

    public function ajaxProcessGetPayments(): void
    {
        $params = [
            'page' => $this->cmsToolsFacade->getValue('page', 1),
            'perPage' => $this->cmsToolsFacade->getValue('perPage', 20),
            'orderBy' => $this->cmsToolsFacade->getValue('orderBy', 'date_add'),
            'orderDirection' => $this->cmsToolsFacade->getValue('orderDirection', 'DESC'),
            'search' => $this->cmsToolsFacade->getValue('search', ''),
            'orderId' => $this->cmsToolsFacade->getValue('orderId', ''),
            'date' => $this->cmsToolsFacade->getValue('date', ''),
            'dateFrom' => $this->cmsToolsFacade->getValue('dateFrom', ''),
            'dateTo' => $this->cmsToolsFacade->getValue('dateTo', ''),
            'customerEmail' => $this->cmsToolsFacade->getValue('customerEmail', ''),
            'customerName' => $this->cmsToolsFacade->getValue('customerName', ''),
            'paymentId' => $this->cmsToolsFacade->getValue('paymentId', ''),
            'status' => $this->cmsToolsFacade->getValue('status', ''),
            'paymentMethod' => $this->cmsToolsFacade->getValue('paymentMethod', ''),
        ];

        $result = $this->paymentsListService->getPayments($params);

        $this->ajaxSuccessResponse($result);
    }

    public function ajaxProcessGetPayment(): void
    {
        $paymentId = (int) $this->cmsToolsFacade->getValue('payment_id', 0);

        if ($paymentId <= 0) {
            $this->ajaxErrorResponse($this->trans('Payment ID is required', [], 'Modules.Payserapayments.Global'), 400);

            return;
        }

        $orderDetails = $this->paymentsListService->getPaymentDetails($paymentId);

        if ($orderDetails === null) {
            $this->ajaxErrorResponse($this->trans('Payment not found', [], 'Modules.Payserapayments.Global'), 404);

            return;
        }

        $this->ajaxSuccessResponse($orderDetails);
    }

    public function ajaxProcessGetPaymentStatuses(): void
    {
        $page = (int) $this->cmsToolsFacade->getValue('page', 1);
        $perPage = (int) $this->cmsToolsFacade->getValue('perPage', 20);

        $statuses = $this->paymentStatusPollingService->getPaymentStatuses($page, $perPage);

        $this->ajaxSuccessResponse($statuses);
    }

    public function ajaxProcessGetDiagnostics(): void
    {
        $this->ajaxSuccessResponse($this->diagnosticManager->getSections());
    }

    public function ajaxProcessDownloadDiagnosticReport(): void
    {
        $report = $this->diagnosticReportGenerator->generateReport();
        $filename = sprintf('paysera-diagnostic-result-%s.txt', gmdate('Y-m-d_H-i-s'));

        header('Content-Type: text/plain; charset=utf-8');
        header(sprintf('Content-Disposition: attachment; filename="%s"', $filename));
        header('Cache-Control: no-store, no-cache, must-revalidate');
        header('Pragma: no-cache');
        header(sprintf('Content-Length: %d', strlen($report)));

        $this->ajaxResponse($report);
    }

    private function isPostRequest(): bool
    {
        return Request::createFromGlobals()->isMethod('POST');
    }

    /**
     * @param array<string, mixed> $data
     */
    private function ajaxSuccessResponse(array $data): void
    {
        header('Content-Type: application/json');

        $content = json_encode([
            'success' => true,
            'data' => $data,
        ]);

        $this->ajaxResponse($content);
    }

    private function ajaxErrorResponse(string $message, int $statusCode = 400): void
    {
        header('Content-Type: application/json');
        http_response_code($statusCode);

        $content = json_encode([
            'success' => false,
            'error' => $message,
        ]);

        $this->ajaxResponse($content);
    }

    /**
     * Send AJAX response - compatible with PrestaShop 8.x and 9.x
     */
    private function ajaxResponse(string $content): void
    {
        if (method_exists($this, 'ajaxDie')) {
            $this->ajaxDie($content);
        } else {
            exit($content);
        }
    }

    /**
     * @return array<string, mixed>|null
     */
    private function getJsonInput(): ?array
    {
        $rawInput = $this->cmsToolsFacade->fileGetContents('php://input');

        if ($rawInput === '' || $rawInput === false) {
            return null;
        }

        $data = json_decode($rawInput, true);

        if (!is_array($data)) {
            return null;
        }

        return $data;
    }
}
