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

namespace Simplyin\Payment\Controller\Api;

use Magento\Framework\App\Request\InvalidRequestException;
use Magento\Framework\App\RequestInterface;

/**
 * Trait for CSRF-aware API controllers
 *
 * Relies on Magento's native form_key validation. Magento's CsrfValidator reads
 * the form_key via $request->getParam('form_key'), which only sees query/form-encoded
 * params and NOT a raw application/json body. Since these API controllers receive a
 * JSON payload (with the form_key inside the body, or in the X-Csrf-Form-Key header),
 * this trait surfaces that form_key into the request params and then defers to
 * Magento's default CsrfValidator, which validates it against the session form_key.
 */
trait CsrfAwareApiTrait
{
    /**
     * Create CSRF validation exception response
     *
     * Returns null to use Magento's default 403 handling.
     *
     * @param RequestInterface $request
     * @return InvalidRequestException|null
     */
    public function createCsrfValidationException(RequestInterface $request): ?InvalidRequestException
    {
        return null;
    }

    /**
     * Validate request for CSRF protection using Magento's native form_key
     *
     * Surfaces the form_key from the JSON body (or the X-Csrf-Form-Key header) into the
     * request params when it is not already a standard param, then returns null to defer
     * to Magento's default CsrfValidator. The native validator compares the form_key
     * against the session form_key, so this trait performs no validation of its own.
     *
     * @param RequestInterface $request
     * @return bool|null
     */
    public function validateForCsrf(RequestInterface $request): ?bool
    {
        // Only surface a form_key when one is not already present as a request param.
        // A strict null check (not truthiness) lets an explicitly provided but empty/invalid
        // form_key fall through to the native validator for rejection, rather than being overridden.
        if ($request->getParam('form_key') === null) {
            $formKey = $this->extractFormKey($request);
            if ($formKey !== null) {
                $request->setParams(array_merge($request->getParams(), ['form_key' => $formKey]));
            }
        }

        // Defer to Magento's native form_key validation.
        return null;
    }

    /**
     * Extract the form_key sent by the frontend AJAX client
     *
     * Prefers the explicit X-Csrf-Form-Key header, then falls back to a form_key
     * field inside the JSON request body.
     *
     * @param RequestInterface $request
     * @return string|null
     */
    private function extractFormKey(RequestInterface $request): ?string
    {
        $header = trim((string)$request->getHeader('X-Csrf-Form-Key'));
        if ($header !== '') {
            return $header;
        }

        $content = $request->getContent();
        if ($content) {
            $data = json_decode($content, true);
            if (is_array($data) && isset($data['form_key'])) {
                $bodyFormKey = trim((string)$data['form_key']);
                if ($bodyFormKey !== '') {
                    return $bodyFormKey;
                }
            }
        }

        return null;
    }
}
