<?php
/**
 * Copyright © Simplyin. All rights reserved.
 */
declare(strict_types=1);

namespace Simplyin\Payment\Model\Resolver;

use Magento\Framework\GraphQl\Config\Element\Field;
use Magento\Framework\GraphQl\Schema\Type\ResolveInfo;
use Magento\Sales\Api\OrderRepositoryInterface;
use Magento\Framework\Api\SearchCriteriaBuilder;
use Simplyin\Payment\Helper\ApiClient;
use Psr\Log\LoggerInterface;

/**
 * Resolver: simplyinCheckPaymentStatus query
 */
class CheckPaymentStatus extends AbstractResolver
{
    /**
     * @var ApiClient
     */
    private ApiClient $apiClient;

    /**
     * @var OrderRepositoryInterface
     */
    private OrderRepositoryInterface $orderRepository;

    /**
     * @var SearchCriteriaBuilder
     */
    private SearchCriteriaBuilder $searchCriteriaBuilder;

    /**
     * @param ApiClient $apiClient
     * @param OrderRepositoryInterface $orderRepository
     * @param SearchCriteriaBuilder $searchCriteriaBuilder
     * @param LoggerInterface $logger
     */
    public function __construct(
        ApiClient $apiClient,
        OrderRepositoryInterface $orderRepository,
        SearchCriteriaBuilder $searchCriteriaBuilder,
        LoggerInterface $logger
    ) {
        parent::__construct($logger);
        $this->apiClient             = $apiClient;
        $this->orderRepository       = $orderRepository;
        $this->searchCriteriaBuilder = $searchCriteriaBuilder;
    }

    /**
     * @inheritdoc
     */
    public function resolve(Field $field, $context, ResolveInfo $info, ?array $value = null, ?array $args = null): array
    {
        $paymentId = $args['payment_id'] ?? '';
        $authToken = $args['auth_token'] ?? '';
        $orderId   = $args['order_id'] ?? '';

        try {
            // Try local order status first
            if ($orderId) {
                $local = $this->getLocalStatus($orderId);
                if ($local) {
                    if (in_array($local['status'], ['COMPLETED', 'PAID', 'SUCCESS', 'FAILED', 'REJECTED', 'CANCELLED', 'CANCELED'], true)) {
                        return $local;
                    }
                    if (in_array($local['order_state'] ?? '', [\Magento\Sales\Model\Order::STATE_PROCESSING, \Magento\Sales\Model\Order::STATE_COMPLETE], true)) {
                        $local['status'] = 'COMPLETED';
                        return $local;
                    }
                }
            }

            if (empty($paymentId)) {
                return [
                    'success'   => true,
                    'status'    => 'PENDING',
                    'message'   => 'Waiting for payment confirmation',
                    'payment_id' => null,
                ];
            }

            $response = $this->apiClient->getPaymentStatus($paymentId, $authToken);

            if (!$response['success']) {
                return ['success' => true, 'status' => 'PENDING', 'message' => 'Waiting for payment confirmation', 'payment_id' => $paymentId];
            }

            $status = $this->mapStatus($response['status'] ?? 'PENDING');

            return [
                'success'    => true,
                'message'    => null,
                'payment_id' => $paymentId,
                'status'     => $status,
            ];
        } catch (\Exception $e) {
            $this->logger->error('SimplyIN GraphQL CheckPaymentStatus: ' . $e->getMessage());
            return ['success' => true, 'status' => 'PENDING', 'message' => 'Waiting for payment confirmation', 'payment_id' => $paymentId];
        }
    }

    /**
     * Get payment status from local Magento order
     *
     * @param string $orderId
     * @return array|null
     */
    private function getLocalStatus(string $orderId): ?array
    {
        try {
            $order = $this->loadOrderForStatus($orderId);
            if (!$order) {
                return null;
            }

            $payment        = $order->getPayment();
            $simplyinStatus = $payment ? $payment->getAdditionalInformation('simplyin_payment_status') : null;
            $orderState     = $order->getState();

            $status = $this->mapLocalStatus($simplyinStatus, $orderState);

            return [
                'success'          => true,
                'status'           => $status,
                'order_id'         => $order->getIncrementId(),
                'order_state'      => $orderState,
                'simplyin_status'  => $simplyinStatus,
                'webhook_received' => $payment ? $payment->getAdditionalInformation('simplyin_webhook_received') : null,
                'source'           => 'local',
            ];
        } catch (\Exception $e) {
            return null;
        }
    }

    /**
     * Load order by entity ID or increment ID
     *
     * @param string $orderId
     * @return \Magento\Sales\Api\Data\OrderInterface|null
     */
    private function loadOrderForStatus(string $orderId)
    {
        $order = null;
        if (is_numeric($orderId)) {
            try {
                $order = $this->orderRepository->get((int)$orderId);
            } catch (\Exception $e) { // phpcs:ignore Magento2.CodeAnalysis.EmptyBlock.DetectedCatch -- intentional: order may not exist by entity ID, fall through to increment-ID lookup below
                // not found by entity id
            }
        }
        if (!$order) {
            $criteria = $this->searchCriteriaBuilder->addFilter('increment_id', $orderId)->create();
            $list     = $this->orderRepository->getList($criteria);
            if ($list->getTotalCount() > 0) {
                $items = $list->getItems();
                $order = reset($items);
            }
        }

        return $order;
    }

    /**
     * Map SimplyIN/order state to standard payment status
     *
     * @param string|null $simplyinStatus
     * @param string|null $orderState
     * @return string
     */
    private function mapLocalStatus($simplyinStatus, $orderState): string
    {
        $status = 'PENDING';
        if (in_array($simplyinStatus, ['PAID', 'COMPLETED', 'SUCCESS'], true)) {
            $status = 'COMPLETED';
        } elseif (in_array($simplyinStatus, ['FAILED', 'REJECTED', 'CANCELLED', 'CANCELED'], true)) {
            $status = 'FAILED';
        } elseif (in_array($orderState, [\Magento\Sales\Model\Order::STATE_PROCESSING, \Magento\Sales\Model\Order::STATE_COMPLETE], true)) {
            $status = 'COMPLETED';
        } elseif ($orderState === \Magento\Sales\Model\Order::STATE_CANCELED) {
            $status = 'FAILED';
        }

        return $status;
    }

    /**
     * Map raw API status to standard status
     *
     * @param string $status
     * @return string
     */
    private function mapStatus(string $status): string
    {
        $map = [
            'PAID' => 'COMPLETED', 'COMPLETED' => 'COMPLETED', 'SUCCESS' => 'COMPLETED',
            'CONFIRMED' => 'COMPLETED', 'APPROVED' => 'COMPLETED',
            'REJECTED' => 'FAILED', 'FAILED' => 'FAILED', 'CANCELLED' => 'FAILED',
            'CANCELED' => 'FAILED', 'DECLINED' => 'FAILED', 'ERROR' => 'FAILED',
        ];
        return $map[strtoupper($status)] ?? 'PENDING';
    }
}
