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

namespace Simplyin\Payment\Controller\Api;

use Magento\Framework\App\Action\HttpPostActionInterface;
use Magento\Framework\App\CsrfAwareActionInterface;
use Magento\Framework\App\RequestInterface;
use Magento\Framework\Controller\Result\JsonFactory;
use Simplyin\Payment\Helper\ApiClient;
use Simplyin\Payment\Service\ParcelLockerFilter;

/**
 * Verify OTP controller
 *
 * Verifies OTP code for user authentication
 */
class VerifyOtp implements HttpPostActionInterface, CsrfAwareActionInterface
{
    use CsrfAwareApiTrait;

    /**
     * @var JsonFactory
     */
    private JsonFactory $resultJsonFactory;

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

    /**
     * @var RequestInterface
     */
    private RequestInterface $request;

    /**
     * @var ParcelLockerFilter
     */
    private ParcelLockerFilter $parcelLockerFilter;

    /**
     * @param JsonFactory $resultJsonFactory
     * @param ApiClient $apiClient
     * @param RequestInterface $request
     * @param ParcelLockerFilter $parcelLockerFilter
     */
    public function __construct(
        JsonFactory $resultJsonFactory,
        ApiClient $apiClient,
        RequestInterface $request,
        ParcelLockerFilter $parcelLockerFilter
    ) {
        $this->resultJsonFactory = $resultJsonFactory;
        $this->apiClient = $apiClient;
        $this->request = $request;
        $this->parcelLockerFilter = $parcelLockerFilter;
    }

    /**
     * Execute verify OTP action
     *
     * @return \Magento\Framework\Controller\Result\Json
     */
    public function execute()
    {
        $result = $this->resultJsonFactory->create();

        try {
            $data = json_decode($this->request->getContent(), true);
            $email = $data['email'] ?? '';
            $code = $data['code'] ?? '';

            if (empty($email) || empty($code)) {
                return $result->setData([
                    'success' => false,
                    'message' => __('Email and OTP code are required')
                ]);
            }

            $response = $this->apiClient->verifyOtp($email, $code);

            // Guard: a 2xx with an empty/non-JSON body makes `data` null (json_decode); read the
            // shape only from a confirmed array so isCodeValid/authToken/userData never dereference
            // a null offset (defensive vs Magento's warning-escalation, even though empty()/?? suppress).
            $data = is_array($response['data'] ?? null) ? $response['data'] : [];
            $isCodeValid = !empty($data['isCodeValid']);
            $authToken = $data['authToken'] ?? '';

            if ($response['success'] && ($authToken !== '' || $isCodeValid)) {
                $userData = $data['data'] ?? [];

                // Fetch user data / cards only for an authenticated response.
                // A guest-degrade response (valid code, no auth token) carries no
                // user data and must not call getUserData() with an empty token.
                if ($authToken !== '') {
                    $userData = $this->resolveUserData($authToken, $userData);
                }

                return $result->setData([
                    'success' => true,
                    'authToken' => $authToken,
                    'isCodeValid' => $isCodeValid,
                    'userData' => $userData,
                    'message' => __('OTP verified successfully')
                ]);
            }

            return $result->setData([
                'success' => false,
                'message' => $response['error'] ?? __('Invalid OTP')
            ]);
        } catch (\Exception $e) {
            return $result->setData([
                'success' => false,
                'message' => __('An unexpected error occurred. Please try again.')
            ]);
        }
    }

    /**
     * Resolve full user data for an authenticated response.
     *
     * @param string $authToken Non-empty auth token.
     * @param mixed $fallback User data to fall back to when the fetch fails (may be a non-array
     *                        when the backend body is empty/scalar — kept untyped to preserve the
     *                        original inline tolerance; the is_array() guard below still applies).
     * @return mixed
     */
    private function resolveUserData(string $authToken, mixed $fallback): mixed
    {
        $userData = $fallback;

        $userDataResponse = $this->apiClient->getUserData($authToken);
        if ($userDataResponse['success']) {
            $userData = $userDataResponse['data'];
            if (isset($userData['data'])) {
                $userData = $userData['data'];
            }
        }
        if (is_array($userData)) {
            $userData = $this->parcelLockerFilter->filterUserDataParcelLockers($userData);
        }

        return $userData;
    }
}
