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

namespace Simplyin\Payment\Helper;

use Simplyin\Payment\Service\Api\AccountApiClient;
use Simplyin\Payment\Service\Api\AddressParcelApiClient;
use Simplyin\Payment\Service\Api\ApiTransport;
use Simplyin\Payment\Service\Api\OrderApiClient;
use Simplyin\Payment\Service\Api\PaymentApiClient;

/**
 * API Client Helper
 *
 * Facade delegating all SimplyIN API communication to domain sub-clients.
 * Public API is preserved so existing callers require no changes.
 */
class ApiClient
{
    /**
     * Config paths, kept for backward compatibility with external callers.
     * ApiTransport is the single source of truth; these alias to it.
     */
    public const XML_PATH_API_BASE_URL = ApiTransport::XML_PATH_API_BASE_URL;
    public const XML_PATH_API_KEY = ApiTransport::XML_PATH_API_KEY;
    public const XML_PATH_STORE_NAME = ApiTransport::XML_PATH_STORE_NAME;

    /**
     * @var AccountApiClient
     */
    private AccountApiClient $accountApiClient;

    /**
     * @var OrderApiClient
     */
    private OrderApiClient $orderApiClient;

    /**
     * @var PaymentApiClient
     */
    private PaymentApiClient $paymentApiClient;

    /**
     * @var AddressParcelApiClient
     */
    private AddressParcelApiClient $addressParcelApiClient;

    /**
     * Constructor
     *
     * @param AccountApiClient $accountApiClient
     * @param OrderApiClient $orderApiClient
     * @param PaymentApiClient $paymentApiClient
     * @param AddressParcelApiClient $addressParcelApiClient
     */
    public function __construct(
        AccountApiClient $accountApiClient,
        OrderApiClient $orderApiClient,
        PaymentApiClient $paymentApiClient,
        AddressParcelApiClient $addressParcelApiClient
    ) {
        $this->accountApiClient = $accountApiClient;
        $this->orderApiClient = $orderApiClient;
        $this->paymentApiClient = $paymentApiClient;
        $this->addressParcelApiClient = $addressParcelApiClient;
    }

    /**
     * Submit email to SimplyIN (sends OTP if user exists)
     *
     * @param string $email
     * @return array
     */
    public function submitEmail($email)
    {
        return $this->accountApiClient->submitEmail($email);
    }

    /**
     * Resend OTP via SMS
     *
     * @param string $email
     * @return array
     */
    public function resendOtpViaSms($email)
    {
        return $this->accountApiClient->resendOtpViaSms($email);
    }

    /**
     * Resend OTP via email
     *
     * @param string $email
     * @return array
     */
    public function resendOtpViaEmail($email)
    {
        return $this->accountApiClient->resendOtpViaEmail($email);
    }

    /**
     * Check push notification status
     *
     * @param string $email
     * @param string $notificationTokenId
     * @return array
     */
    public function checkPushStatus($email, $notificationTokenId = '')
    {
        return $this->accountApiClient->checkPushStatus($email, $notificationTokenId);
    }

    /**
     * Verify OTP
     *
     * @param string $email
     * @param string $code
     * @return array
     */
    public function verifyOtp($email, $code)
    {
        return $this->accountApiClient->verifyOtp($email, $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)
    {
        return $this->accountApiClient->createAccount($email, $firstName, $lastName, $phone);
    }

    /**
     * Get user data with auth token
     *
     * @param string $authToken
     * @return array
     */
    public function getUserData($authToken)
    {
        return $this->accountApiClient->getUserData($authToken);
    }

    /**
     * Get payment methods
     *
     * @return array
     */
    public function getPaymentMethods()
    {
        return $this->paymentApiClient->getPaymentMethods();
    }

    /**
     * Create order (for authenticated users)
     *
     * @param array $orderData
     * @param string $authToken
     * @param string $customerEmail
     * @return array
     */
    public function createOrder($orderData, $authToken, $customerEmail = '')
    {
        return $this->orderApiClient->createOrder($orderData, $authToken, $customerEmail);
    }

    /**
     * Create order without account
     *
     * @param array $orderData
     * @param string $authToken
     * @return array
     */
    public function createOrderWithoutAccount($orderData, $authToken)
    {
        return $this->orderApiClient->createOrderWithoutAccount($orderData, $authToken);
    }

    /**
     * Create order and account
     *
     * @param array $orderData
     * @param array $accountData
     * @return array
     */
    public function createOrderAndAccount($orderData, $accountData)
    {
        return $this->orderApiClient->createOrderAndAccount($orderData, $accountData);
    }

    /**
     * Update user data
     *
     * @param array $userData
     * @param string $authToken
     * @return array
     */
    public function updateUserData($userData, $authToken)
    {
        return $this->accountApiClient->updateUserData($userData, $authToken);
    }

    /**
     * Get closest parcel lockers based on coordinates
     *
     * @param float $lat Latitude
     * @param float $lng Longitude
     * @param array $providers Accepted parcel locker providers
     * @param int $limit Number of items to find
     * @param int $radius Search radius in meters
     * @param string $authToken Auth token
     * @return array
     */
    public function getClosestParcelLockers($lat, $lng, $providers = [], $limit = 20, $radius = 5000, $authToken = '')
    {
        return $this->addressParcelApiClient->getClosestParcelLockers($lat, $lng, $providers, $limit, $radius, $authToken);
    }

    /**
     * Get user parcel lockers info from user data
     *
     * @param string $authToken
     * @return array
     */
    public function getUserParcelLockersInfo($authToken)
    {
        return $this->addressParcelApiClient->getUserParcelLockersInfo($authToken);
    }

    /**
     * Get shipping method mapping configuration
     *
     * @return array
     */
    public function getShippingMethodMapping()
    {
        return $this->addressParcelApiClient->getShippingMethodMapping();
    }

    /**
     * Get available parcel locker providers based on admin configuration
     *
     * @return array
     */
    public function getAvailableParcelLockerProviders()
    {
        return $this->addressParcelApiClient->getAvailableParcelLockerProviders();
    }

    /**
     * Search address
     *
     * @param string $query
     * @param string $authToken
     * @return array
     */
    public function searchAddress($query, $authToken)
    {
        return $this->addressParcelApiClient->searchAddress($query, $authToken);
    }

    /**
     * Update order status in SimplyIN
     *
     * @param string $orderId
     * @param string $status
     * @param string $authToken
     * @return array
     */
    public function updateOrderStatus($orderId, $status, $authToken)
    {
        return $this->orderApiClient->updateOrderStatus($orderId, $status, $authToken);
    }

    /**
     * Get available payment methods
     *
     * @return array
     */
    public function getAvailablePaymentMethods()
    {
        return $this->paymentApiClient->getAvailablePaymentMethods();
    }

    /**
     * Get saved cards from user data
     *
     * @param string $authToken
     * @return array
     */
    public function getSavedCards($authToken)
    {
        return $this->paymentApiClient->getSavedCards($authToken);
    }

    /**
     * Get payment methods with full details including iframeUrl, integratorId, and saved cards
     *
     * @param string $authToken User authentication token
     * @return array
     */
    public function getPaymentMethodsWithDetails($authToken)
    {
        return $this->paymentApiClient->getPaymentMethodsWithDetails($authToken);
    }

    /**
     * Get payment status
     *
     * @param string $paymentId The payment ID to check
     * @param string $authToken User authentication token (optional)
     * @return array
     */
    public function getPaymentStatus($paymentId, $authToken = '')
    {
        return $this->paymentApiClient->getPaymentStatus($paymentId, $authToken);
    }

    /**
     * Create payment link (initiate payment)
     *
     * @param array $paymentData
     * @param string|null $authToken
     * @return array
     */
    public function createPaymentLink($paymentData, $authToken = null)
    {
        return $this->paymentApiClient->createPaymentLink($paymentData, $authToken);
    }

    /**
     * Get controller URL
     *
     * @param string $path
     * @return string
     */
    public function getControllerURL(string $path): string
    {
        return $this->orderApiClient->getControllerURL($path);
    }

    /**
     * Get plugin sync info from API
     *
     * @return array
     */
    public function getPluginSyncInfo()
    {
        return $this->orderApiClient->getPluginSyncInfo();
    }

    /**
     * Verify if hashed emails exist in SimplyIN
     *
     * @param array $hashedEmails Array of SHA-256 hashed email addresses
     * @return array
     */
    public function verifyHashedEmailsExist(array $hashedEmails)
    {
        return $this->orderApiClient->verifyHashedEmailsExist($hashedEmails);
    }

    /**
     * Save encrypted order status change to SimplyIN
     *
     * @param string $encryptedContent Encrypted order status data
     * @param string $hashedEmail SHA-256 hashed email with format "--{email}--"
     * @param string|null $plainPayload Plain payload for logging (optional)
     * @param string|null $email Original email for decrypting response (optional)
     * @return array
     */
    public function saveEncryptedOrderStatusChange(string $encryptedContent, string $hashedEmail, ?string $plainPayload = null, ?string $email = null)
    {
        return $this->orderApiClient->saveEncryptedOrderStatusChange($encryptedContent, $hashedEmail, $plainPayload, $email);
    }
}
