<?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\GraphQlAuthorizationException;
use Magento\Framework\GraphQl\Exception\GraphQlInputException;
use Magento\Framework\GraphQl\Schema\Type\ResolveInfo;
use Simplyin\Payment\Service\CheckoutOwnershipGuard;
use Simplyin\Payment\Service\ProcessPaymentService;
use Psr\Log\LoggerInterface;

/**
 * Resolver: simplyinProcessPayment mutation
 *
 * Headless counterpart of the ProcessPayment REST controller. Delegates the
 * payment-first flow to the shared {@see ProcessPaymentService} and flattens the
 * result to the GraphQL output type (dynamic payload kept in raw_json, following
 * the module's raw_json convention).
 */
class ProcessPayment extends AbstractResolver
{
    /**
     * @var ProcessPaymentService
     */
    private ProcessPaymentService $processPaymentService;

    /**
     * @var CheckoutOwnershipGuard
     */
    private CheckoutOwnershipGuard $ownershipGuard;

    /**
     * @param ProcessPaymentService $processPaymentService
     * @param CheckoutOwnershipGuard $ownershipGuard
     * @param LoggerInterface $logger
     */
    public function __construct(
        ProcessPaymentService $processPaymentService,
        CheckoutOwnershipGuard $ownershipGuard,
        LoggerInterface $logger
    ) {
        parent::__construct($logger);
        $this->processPaymentService = $processPaymentService;
        $this->ownershipGuard = $ownershipGuard;
    }

    /**
     * @inheritdoc
     */
    public function resolve(Field $field, $context, ResolveInfo $info, ?array $value = null, ?array $args = null): array
    {
        $args = $args ?? [];
        $this->requireArg($args, 'order_data_json');

        $orderData = json_decode((string)$args['order_data_json'], true);
        // Must be a JSON object (map). Reject non-arrays and JSON lists such as
        // "[1,2]" (empty "[]"/"{}" both decode to [] and are allowed as "no data").
        if (!is_array($orderData) || (array_is_list($orderData) && $orderData !== [])) {
            throw new GraphQlInputException(__('"order_data_json" must be a valid JSON object.'));
        }

        // IDOR guard: an authenticated customer may only act on their
        // own cart. Identity comes from $context (GraphQL is stateless).
        if (!$this->ownershipGuard->isQuoteOwnedBy($this->customerIdFromContext($context), $orderData['quoteId'] ?? null)) {
            throw new GraphQlAuthorizationException(__('Unauthorized access to cart.'));
        }

        try {
            $result = $this->processPaymentService->process([
                'orderData'     => $orderData,
                'authToken'     => $args['auth_token'] ?? '',
                'isNewUser'     => $args['is_new_user'] ?? false,
                'createAccount' => $args['create_account'] ?? false,
                'paymentOnly'   => $args['payment_only'] ?? false,
            ]);
        } catch (\Exception $e) {
            $this->logger->error('SimplyIN GraphQL ProcessPayment: ' . $e->getMessage());
            return $this->errorOutput('An unexpected error occurred. Please try again.');
        }

        return $this->flattenPaymentResult($result);
    }

    /**
     * Flatten a payment-flow result array to the GraphQL output shape.
     *
     * @param array $result
     * @return array
     */
    private function flattenPaymentResult(array $result): array
    {
        $info = $result['paymentInfo'] ?? [];

        return [
            'success'                 => (bool)($result['success'] ?? false),
            'message'                 => isset($result['message']) ? (string)$result['message'] : null,
            'simplyin_order_id'       => $info['simplyin_order_id'] ?? null,
            'payment_id'              => $info['simplyin_payment_id'] ?? null,
            'provider_payment_id'     => $info['simplyin_provider_payment_id'] ?? null,
            'payment_status'          => $info['simplyin_payment_status'] ?? null,
            'redirect_url'            => $info['simplyin_redirect_url'] ?? null,
            'redirect_iframe_allowed' => (bool)($info['simplyin_redirect_iframe_allowed'] ?? false),
            'payment_only'            => (bool)($result['paymentOnly'] ?? false),
            'auth_token'              => $result['authToken'] ?? null,
            // Only the provider payment object — never the order/billing PII the
            // flat fields deliberately omit.
            'raw_json'                => isset($result['payment']) ? json_encode($result['payment']) : null,
        ];
    }
}
