<?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 Psr\Log\LoggerInterface;

/**
 * Get parcel lockers controller
 *
 * Retrieves available parcel lockers from SimplyIN user profile
 * and closest parcel lockers based on coordinates
 */
class GetParcelLockers implements HttpPostActionInterface, CsrfAwareActionInterface
{
    use CsrfAwareApiTrait;

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

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

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

    /**
     * @var LoggerInterface
     */
    private $logger;

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

    /**
     * Execute get parcel lockers action
     *
     * @return \Magento\Framework\Controller\Result\Json
     */
    public function execute()
    {
        $result = $this->resultJsonFactory->create();
        
        try {
            $data = json_decode($this->request->getContent(), true);
            $authToken = $data['authToken'] ?? '';
            $action = $data['action'] ?? 'getUserLockers'; // getUserLockers or getClosest

            if (empty($authToken)) {
                return $result->setData([
                    'success' => false,
                    'message' => __('Authentication required')
                ]);
            }

            // Get available providers from admin configuration
            $availableProviders = $this->apiClient->getAvailableParcelLockerProviders();

            if ($action === 'getClosest') {
                // Get closest parcel lockers based on coordinates
                return $this->getClosestParcelLockers($data, $authToken, $availableProviders, $result);
            } else {
                // Get user's saved parcel lockers from their profile
                return $this->getUserParcelLockers($authToken, $availableProviders, $result);
            }
        } catch (\Exception $e) {
            $this->logger->error('SimplyIN GetParcelLockers: ' . $e->getMessage(), [
                'trace' => $e->getTraceAsString()
            ]);
            return $result->setData([
                'success' => false,
                'message' => __('An unexpected error occurred. Please try again.')
            ]);
        }
    }

    /**
     * Get user's saved parcel lockers from their SimplyIN profile
     *
     * @param string $authToken
     * @param array $availableProviders
     * @param \Magento\Framework\Controller\Result\Json $result
     * @return \Magento\Framework\Controller\Result\Json
     */
    private function getUserParcelLockers($authToken, $availableProviders, $result)
    {
        // First get user data which includes parcel lockers
        $userDataResponse = $this->apiClient->getUserData($authToken);

        if (!$userDataResponse['success']) {
            return $result->setData([
                'success' => false,
                'message' => $userDataResponse['error'] ?? __('Failed to get user data')
            ]);
        }

        // Handle nested data structure: API returns { data: { parcelLockers: [...] } }
        $userData = $userDataResponse['data'] ?? [];
        if (isset($userData['data'])) {
            $userData = $userData['data'];
        }
        $parcelLockers = $userData['parcelLockers'] ?? [];

        // Filter parcel lockers by available providers
        $filteredLockers = $this->filterLockersByProviders($parcelLockers, $availableProviders);

        // Separate into parcel machines and pickup points
        $parcelMachines = [];
        $pickupPoints = [];

        foreach ($filteredLockers as $locker) {
            $serviceType = $locker['service_type'] ?? '';
            if ($serviceType === 'parcel_machine') {
                $parcelMachines[] = $locker;
            } else {
                $pickupPoints[] = $locker;
            }
        }

        // Get shipping method mapping for cost display
        $shippingMapping = $this->apiClient->getShippingMethodMapping();

        return $result->setData([
            'success' => true,
            'parcelMachines' => $parcelMachines,
            'pickupPoints' => $pickupPoints,
            'allLockers' => $filteredLockers,
            'shippingMapping' => $shippingMapping,
            'availableProviders' => $availableProviders,
            'message' => __('Parcel lockers retrieved successfully')
        ]);
    }

    /**
     * Get closest parcel lockers based on coordinates
     *
     * @param array $data
     * @param string $authToken
     * @param array $availableProviders
     * @param \Magento\Framework\Controller\Result\Json $result
     * @return \Magento\Framework\Controller\Result\Json
     */
    private function getClosestParcelLockers($data, $authToken, $availableProviders, $result)
    {
        $coordinates = $data['coordinates'] ?? [];
        $lat = $coordinates['lat'] ?? $coordinates['latitude'] ?? null;
        $lng = $coordinates['lng'] ?? $coordinates['longitude'] ?? null;
        $limit = $data['limit'] ?? $data['numberOfItemsToFind'] ?? 20;
        $radius = $data['radius'] ?? $data['searchRadiusInMeters'] ?? 5000;

        // Handle coordinates validation - allow 0 values but not null/empty
        if ($lat === null || $lng === null || $lat === '' || $lng === '') {
            return $result->setData([
                'success' => false,
                'message' => __('Coordinates are required')
            ]);
        }
        
        // Convert to float
        $lat = (float) $lat;
        $lng = (float) $lng;

        // Use custom providers if provided, otherwise use configured ones
        $providers = !empty($data['providers']) ? $data['providers'] : $availableProviders;

        $response = $this->apiClient->getClosestParcelLockers(
            $lat,
            $lng,
            $providers,
            $limit,
            $radius,
            $authToken
        );

        if (!$response['success']) {
            return $result->setData([
                'success' => false,
                'message' => $response['error'] ?? __('Failed to get closest parcel lockers')
            ]);
        }

        $lockers = $response['data'] ?? [];

        // Separate into parcel machines and pickup points
        $parcelMachines = [];
        $pickupPoints = [];

        foreach ($lockers as $locker) {
            $serviceType = $locker['service_type'] ?? '';
            if ($serviceType === 'parcel_machine') {
                $parcelMachines[] = $locker;
            } else {
                $pickupPoints[] = $locker;
            }
        }

        // Get shipping method mapping for cost display
        $shippingMapping = $this->apiClient->getShippingMethodMapping();

        return $result->setData([
            'success' => true,
            'parcelMachines' => $parcelMachines,
            'pickupPoints' => $pickupPoints,
            'allLockers' => $lockers,
            'shippingMapping' => $shippingMapping,
            'availableProviders' => $availableProviders,
            'message' => __('Closest parcel lockers retrieved successfully')
        ]);
    }

    /**
     * Filter parcel lockers by available providers
     *
     * @param array $lockers
     * @param array $availableProviders
     * @return array
     */
    private function filterLockersByProviders($lockers, $availableProviders)
    {
        if (empty($availableProviders)) {
            return $lockers;
        }

        return array_filter($lockers, function ($locker) use ($availableProviders) {
            $providerName = strtolower($locker['providerName'] ?? '');
            foreach ($availableProviders as $provider) {
                if (stripos($providerName, $provider) !== false || stripos($provider, $providerName) !== false) {
                    return true;
                }
            }
            return false;
        });
    }
}
