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

namespace Simplyin\Payment\Service\Api;

use Magento\Framework\App\ProductMetadataInterface;
use Magento\Framework\Locale\ResolverInterface;
use Magento\Framework\Module\PackageInfo;

/**
 * Account and authentication related SimplyIN API operations.
 */
class AccountApiClient
{
    /**
     * @var ApiTransport
     */
    private ApiTransport $transport;

    /**
     * @var ProductMetadataInterface
     */
    private ProductMetadataInterface $productMetadata;

    /**
     * @var PackageInfo
     */
    private PackageInfo $packageInfo;

    /**
     * @var ResolverInterface
     */
    private ResolverInterface $localeResolver;

    /**
     * Constructor
     *
     * @param ApiTransport $transport
     * @param ProductMetadataInterface $productMetadata
     * @param PackageInfo $packageInfo
     * @param ResolverInterface $localeResolver
     */
    public function __construct(
        ApiTransport $transport,
        ProductMetadataInterface $productMetadata,
        PackageInfo $packageInfo,
        ResolverInterface $localeResolver
    ) {
        $this->transport = $transport;
        $this->productMetadata = $productMetadata;
        $this->packageInfo = $packageInfo;
        $this->localeResolver = $localeResolver;
    }

    /**
     * Merge plugin/shop metadata into an outbound payload so the backend can display it in the
     * merchant panel (shop name, plugin version, platform, shop version, language) — the Magento
     * counterpart of the WooCommerce update_array_with_plugin_info().
     *
     * @param array $data
     * @return array
     */
    private function addPluginInfo(array $data): array
    {
        $data['pluginVersion'] = (string)$this->packageInfo->getVersion('Simplyin_Payment');
        $data['shopName'] = $this->transport->getShopName();
        $data['platform'] = 'Magento';
        $data['shopVersion'] = (string)$this->productMetadata->getVersion();
        $data['lng'] = strtoupper(substr((string)$this->localeResolver->getLocale(), 0, 2));

        return $data;
    }

    /**
     * Submit email to SimplyIN (sends OTP if user exists)
     *
     * Initial submission - sends OTP via default method (SMS or push notification)
     *
     * @param string $email
     * @return array
     */
    public function submitEmail($email)
    {
        $payload = $this->addPluginInfo([
            'email' => $email
        ]);

        $response = $this->transport->makeRequest('checkout/submitEmail', 'POST', $payload);

        if (!$response['success']) {
            if (isset($response['response'])) {
                $responseData = json_decode($response['response'], true);
                if (isset($responseData['message']) &&
                    (strpos($responseData['message'], 'User not found') !== false ||
                        strpos($responseData['message'], 'not found') !== false)) {
                    return [
                        'success' => false,
                        'error' => 'USER_NOT_FOUND'  // Return plain string, not translated
                    ];
                }
            }
        }

        return $response;
    }

    /**
     * Resend OTP via SMS
     *
     * Forces SMS delivery even if user prefers push notifications
     *
     * @param string $email
     * @return array
     */
    public function resendOtpViaSms($email)
    {
        $payload = $this->addPluginInfo([
            'email' => $email,
            'forceSms' => true
        ]);

        return $this->transport->makeRequest('checkout/submitEmail', 'POST', $payload);
    }

    /**
     * Resend OTP via email
     *
     * Uses different endpoint specifically for email delivery
     *
     * @param string $email
     * @return array
     */
    public function resendOtpViaEmail($email)
    {
        $payload = [
            'email' => $email
        ];

        return $this->transport->makeRequest('checkout/resend-checkout-code-via-email', 'POST', $payload);
    }

    /**
     * Check push notification status
     * Polls to check if user has approved the push notification login
     * Uses the same endpoint as WordPress plugin: checkIfSubmitEmailPushNotificationWasConfirmedCommerce
     *
     * @param string $email
     * @param string $notificationTokenId
     * @return array
     */
    public function checkPushStatus($email, $notificationTokenId = '')
    {
        $payload = [
            'email' => $email
        ];

        if (!empty($notificationTokenId)) {
            $payload['notificationTokenId'] = $notificationTokenId;
        }

        // Use the correct API endpoint matching WordPress plugin
        return $this->transport->makeRequest('checkout/checkIfSubmitEmailPushNotificationWasConfirmedCommerce', 'POST', $payload);
    }

    /**
     * Verify OTP
     *
     * @param string $email
     * @param string $code
     * @return array
     */
    public function verifyOtp($email, $code)
    {
        return $this->transport->makeRequest('checkout/submitCheckoutCodeCommerce', 'POST', [
            'email' => $email,
            'code' => $code
        ]);
    }

    /**
     * Create new account
     *
     * @param string $email
     * @param string $firstName
     * @param string $lastName
     * @param string $phone
     * @return array
     */
    public function createAccount($email, $firstName, $lastName, $phone)
    {
        $submitResponse = $this->submitEmail($email);

        if ($submitResponse['success'] ||
            (isset($submitResponse['error']) && $submitResponse['error'] === 'USER_NOT_FOUND')) {

            $orderData = [
                'newAccountData' => [
                    'email' => $email,
                    'phoneNumber' => $phone,
                    'name' => $firstName,
                    'surname' => $lastName,
                    'language' => 'EN',
                    'authStrategy' => 'sms'
                ],
                'newOrderData' => [
                    'price' => 0.01,
                    'currency' => 'PLN',
                    'items' => [[
                        'name' => 'Account Registration',
                        'url' => 'https://magento-item.com',
                        'price' => 0.01,
                        'quantity' => 1,
                        'currency' => 'PLN'
                    ]],
                    'placedDuringAccountCreation' => true,
                    'shopOrderNumber' => 'REG-' . time() . '-' . random_int(1000, 9999),
                    'shopUserEmail' => $email
                ],
                'merchantApiKey' => $this->transport->getApiKey(),
                'shopName' => $this->transport->getShopName() ?: 'Magento Store',
                'shopUserEmail' => $email
            ];

            $response = $this->transport->makeRequest('checkout/createOrderAndAccount', 'POST', $orderData);

            if ($response['success']) {
                return [
                    'success' => true,
                    'message' => __('Account created successfully. Please check your email for OTP.'),
                    'data' => $response['data'],
                    'requiresOtp' => true
                ];
            }

            return $response;
        }

        return $submitResponse;
    }

    /**
     * Get user data with auth token
     *
     * @param string $authToken
     * @return array
     */
    public function getUserData($authToken)
    {
        $url = $this->transport->getApiBaseUrl() . '/userDataCommerce';

        if ($authToken) {
            $url .= '?api_token=' . urlencode($authToken);
        }

        $this->transport->getCurl()->setHeaders([
            'Content-Type' => 'application/json',
            'Origin' => $this->transport->getOrigin(),
            'X-Auth-Merchant-Api-Key' => $this->transport->getApiKey()
        ]);

        try {
            $this->transport->getCurl()->get($url);
            $response = $this->transport->getCurl()->getBody();
            $statusCode = $this->transport->getCurl()->getStatus();

            if ($statusCode >= 200 && $statusCode < 300) {
                return [
                    'success' => true,
                    'data' => json_decode($response, true)
                ];
            } else {
                $decoded = json_decode($response, true);
                return [
                    'success' => false,
                    'error' => $decoded['message'] ?? __('Failed to get user data'),
                    'response' => $response
                ];
            }
        } catch (\Exception $e) {
            return [
                'success' => false,
                'error' => $e->getMessage()
            ];
        }
    }

    /**
     * Update user data
     *
     * @param array $userData
     * @param string $authToken
     * @return array
     */
    public function updateUserData($userData, $authToken)
    {
        $url = $this->transport->getApiBaseUrl() . '/userData';

        if ($authToken) {
            $url .= '?api_token=' . urlencode($authToken);
        }

        $this->transport->getCurl()->setHeaders([
            'Content-Type' => 'application/json',
            'Origin' => $this->transport->getOrigin(),
            'X-Auth-Merchant-Api-Key' => $this->transport->getApiKey()
        ]);

        try {
            $this->transport->getCurl()->setOption(CURLOPT_CUSTOMREQUEST, 'PATCH');
            $this->transport->getCurl()->setOption(CURLOPT_POSTFIELDS, json_encode($userData));
            $this->transport->getCurl()->get($url);

            $response = $this->transport->getCurl()->getBody();
            $statusCode = $this->transport->getCurl()->getStatus();

            if ($statusCode >= 200 && $statusCode < 300) {
                return [
                    'success' => true,
                    'data' => json_decode($response, true)
                ];
            } else {
                $decoded = json_decode($response, true);
                return [
                    'success' => false,
                    'error' => $decoded['message'] ?? __('Failed to update user data'),
                    'response' => $response
                ];
            }
        } catch (\Exception $e) {
            return [
                'success' => false,
                'error' => $e->getMessage()
            ];
        }
    }
}
