<?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\Exception\GraphQlInputException;
use Magento\Framework\GraphQl\Schema\Type\ResolveInfo;
use Magento\Quote\Api\CartRepositoryInterface;
use Magento\Quote\Api\CartManagementInterface;
use Magento\Quote\Model\QuoteIdMaskFactory;
use Magento\Sales\Api\OrderRepositoryInterface;
use Magento\Customer\Model\Session as CustomerSession;
use Simplyin\Payment\Helper\ApiClient;
use Psr\Log\LoggerInterface;

/**
 * Resolver: simplyinPlaceMagentoOrder mutation
 */
class PlaceMagentoOrder extends AbstractResolver
{
    /**
     * @var CartRepositoryInterface
     */
    private CartRepositoryInterface $quoteRepository;

    /**
     * @var CartManagementInterface
     */
    private CartManagementInterface $cartManagement;

    /**
     * @var QuoteIdMaskFactory
     */
    private QuoteIdMaskFactory $quoteIdMaskFactory;

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

    /**
     * @var ApiClient
     */
    private ApiClient $apiClient;

    /**
     * @var CustomerSession
     */
    private CustomerSession $customerSession;

    /**
     * @param CartRepositoryInterface $quoteRepository
     * @param CartManagementInterface $cartManagement
     * @param QuoteIdMaskFactory $quoteIdMaskFactory
     * @param OrderRepositoryInterface $orderRepository
     * @param ApiClient $apiClient
     * @param CustomerSession $customerSession
     * @param LoggerInterface $logger
     */
    public function __construct(
        CartRepositoryInterface $quoteRepository,
        CartManagementInterface $cartManagement,
        QuoteIdMaskFactory $quoteIdMaskFactory,
        OrderRepositoryInterface $orderRepository,
        ApiClient $apiClient,
        CustomerSession $customerSession,
        LoggerInterface $logger
    ) {
        parent::__construct($logger);
        $this->quoteRepository    = $quoteRepository;
        $this->cartManagement     = $cartManagement;
        $this->quoteIdMaskFactory = $quoteIdMaskFactory;
        $this->orderRepository    = $orderRepository;
        $this->apiClient          = $apiClient;
        $this->customerSession    = $customerSession;
    }

    /**
     * @inheritdoc
     */
    public function resolve(Field $field, $context, ResolveInfo $info, ?array $value = null, ?array $args = null): array
    {
        $quoteId = $args['quote_id'] ?? '';
        if (empty($quoteId)) {
            throw new GraphQlInputException(__('quote_id is required.'));
        }

        try {
            // Resolve masked quote ID for guests
            $quoteId = $this->resolveQuoteId($quoteId);

            $quote = $this->quoteRepository->get($quoteId);

            if (!$quote->getId()) {
                return $this->errorOutput('Quote not found');
            }

            // Cart ownership check for logged-in customers
            $ownershipError = $this->verifyCartOwnership($quote);
            if ($ownershipError !== null) {
                return $ownershipError;
            }

            if (!$quote->getIsActive()) {
                return $this->errorOutput('Quote is no longer active');
            }

            // Set payment method and store SimplyIN info
            $payment = $quote->getPayment();
            $payment->setMethod('simplyin_payment');

            $paymentInfo = $this->extractPaymentInfo($args);
            foreach ($paymentInfo as $key => $val) {
                $payment->setAdditionalInformation($key, $val);
            }

            $this->quoteRepository->save($quote);

            $orderId = $this->cartManagement->placeOrder((int)$quoteId);
            if (!$orderId) {
                return $this->errorOutput('Failed to create Magento order');
            }

            $order = $this->orderRepository->get($orderId);

            return $this->finalizeOrder($order, $paymentInfo, $args, $orderId);
        } catch (\Exception $e) {
            $this->logger->error('SimplyIN GraphQL PlaceMagentoOrder: ' . $e->getMessage());
            return $this->errorOutput('An unexpected error occurred. Please try again.');
        }
    }

    /**
     * Extract payment info from GraphQL args
     *
     * @param array $args
     * @return array
     */
    private function extractPaymentInfo(array $args): array
    {
        $map = [
            'simplyin_order_id'              => 'simplyin_order_id',
            'simplyin_payment_id'            => 'simplyin_payment_id',
            'provider_payment_id'            => 'simplyin_provider_payment_id',
            'payment_status'                 => 'simplyin_payment_status',
            'redirect_url'                   => 'simplyin_redirect_url',
            'card_last4'                     => 'simplyin_card_last4',
            'card_brand'                     => 'simplyin_card_brand',
            'payment_type'                   => 'simplyin_payment_type',
        ];

        $info = [];
        foreach ($map as $argKey => $infoKey) {
            if (!empty($args[$argKey])) {
                $info[$infoKey] = $args[$argKey];
            }
        }

        if (isset($args['redirect_iframe_allowed'])) {
            $info['simplyin_redirect_iframe_allowed'] = $args['redirect_iframe_allowed'] ? '1' : '0';
        }

        return $info;
    }

    /**
     * Resolve masked quote ID to actual ID for guests
     *
     * @param mixed $quoteId
     * @return mixed
     */
    private function resolveQuoteId($quoteId)
    {
        // Resolve masked quote ID for guests
        if (!is_numeric($quoteId)) {
            $mask = $this->quoteIdMaskFactory->create()->load($quoteId, 'masked_id');
            if ($mask->getQuoteId()) {
                $quoteId = $mask->getQuoteId();
            }
        }

        return $quoteId;
    }

    /**
     * Cart ownership check for logged-in customers
     *
     * @param \Magento\Quote\Api\Data\CartInterface $quote
     * @return array|null Error output or null when ownership is valid
     */
    private function verifyCartOwnership($quote): ?array
    {
        // Cart ownership check for logged-in customers
        if ($this->customerSession->isLoggedIn()) {
            $customerId = (int)$this->customerSession->getCustomerId();
            if ((int)$quote->getCustomerId() !== $customerId) {
                return $this->errorOutput('Unauthorized access to cart');
            }
        }

        return null;
    }

    /**
     * Persist payment info on the placed order, notify SimplyIN and build success output
     *
     * @param \Magento\Sales\Api\Data\OrderInterface $order
     * @param array $paymentInfo
     * @param array $args
     * @param mixed $orderId
     * @return array
     */
    private function finalizeOrder($order, array $paymentInfo, array $args, $orderId): array
    {
        // Persist payment info on the placed order
        $orderPayment = $order->getPayment();
        foreach ($paymentInfo as $key => $val) {
            $orderPayment->setAdditionalInformation($key, $val);
        }
        $this->orderRepository->save($order);

        // Notify SimplyIN if order ID and auth token provided
        $simplyinOrderId = $args['simplyin_order_id'] ?? '';
        $authToken       = $args['auth_token'] ?? '';
        if ($simplyinOrderId && $authToken) {
            $this->apiClient->updateOrderStatus($simplyinOrderId, 'CONFIRMED', $authToken);
        }

        return [
            'success'      => true,
            'message'      => 'Magento order created successfully',
            'order_id'     => (int)$orderId,
            'increment_id' => $order->getIncrementId(),
        ];
    }
}
