<?php

namespace Autogedal\TbiBank\Cron;

use Autogedal\TbiBank\Model\PaymentMethod;
use Autogedal\TbiBank\Model\ApplicationRegistry;
use Autogedal\TbiBank\Model\ApprovalAccounting;
use Autogedal\TbiBank\Model\ApprovalConfig;
use Autogedal\TbiBank\Model\Environment;
use Magento\Framework\Exception\LocalizedException;
use Magento\Framework\HTTP\Client\Curl;
use Magento\Sales\Model\Order;
use Magento\Sales\Model\OrderFactory;
use Magento\Sales\Model\ResourceModel\Order as OrderResource;
use Psr\Log\LoggerInterface;

class CheckApprovals
{
    public function __construct(
        private ApprovalConfig $config,
        private ApplicationRegistry $registry,
        private Environment $environment,
        private ApprovalAccounting $accounting,
        private OrderFactory $orderFactory,
        private OrderResource $orderResource,
        private Curl $curl,
        private LoggerInterface $logger
    ) {
    }

    public function execute(): void
    {
        if (!$this->config->pollingEnabled()) {
            return;
        }
        foreach ($this->registry->getCandidates($this->config->getBatchSize()) as $row) {
            $orderId = (int) $row['order_id'];
            try {
                $order = $this->orderFactory->create();
                $this->orderResource->load($order, $orderId);
                if ($order->getStatus() !== ApprovalConfig::WAITING_STATUS
                    || $order->getState() !== ApprovalConfig::ORDER_STATE || !$order->getPayment()
                    || $order->getPayment()->getMethod() !== PaymentMethod::CODE
                ) {
                    $this->registry->checked($orderId);
                    continue;
                }
                if (!hash_equals((string) $row['account_fingerprint'], $this->environment->getAccountFingerprint($order->getStoreId()))) {
                    throw new LocalizedException(__('The application belongs to a different TBI environment or account.'));
                }
                $credentials = $this->environment->getCredentials($order->getStoreId());
                $this->curl->setHeaders(['Content-Type' => 'application/json']);
                $this->curl->setOption(CURLOPT_CONNECTTIMEOUT, 3);
                $this->curl->setTimeout(10);
                $this->curl->post($this->environment->getOrigin() . '/api/GetApplicationStatus', json_encode([
                    'reseller_code' => $credentials['reseller_code'],
                    'reseller_key' => $credentials['reseller_key'],
                    'order_id' => (int) $row['provider_order_id'],
                    'token' => $this->registry->token($row),
                ]));
                $response = json_decode($this->curl->getBody(), true);
                if ($this->curl->getStatus() !== 200 || !is_array($response)
                    || !isset($response['error']) || (int) $response['error'] !== 0
                    || (string) ($response['store_order_id'] ?? '') !== (string) $order->getIncrementId()
                    || !is_string($response['status'] ?? null) || $response['status'] === ''
                    || strlen($response['status']) > 255
                ) {
                    throw new LocalizedException(__('TBI returned an invalid application status response.'));
                }
                $status = $response['status'];
                if (in_array($status, $this->config->getRemoteApprovedStatuses(), true)) {
                    $this->accounting->approve((string) $order->getIncrementId(), (string) __('Approved'));
                }
                $this->registry->checked($orderId, $status);
            } catch (\Throwable $exception) {
                // Do not log the response, personal data, tokens or credentials.
                $this->logger->warning('TBI approval polling failed for Magento order {order_id}.', ['order_id' => $orderId]);
                $this->registry->checked($orderId);
            }
        }
    }
}
