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

namespace Simplyin\Payment\Observer;

use Magento\Framework\Event\Observer;
use Magento\Framework\Event\ObserverInterface;
use Magento\Sales\Model\Order\Shipment\Track;
use Magento\Framework\App\Config\ScopeConfigInterface;
use Magento\Store\Model\ScopeInterface;
use Simplyin\Payment\Helper\ApiClient;
use Simplyin\Payment\Helper\Encryption;
use Simplyin\Payment\Model\ResourceModel\OrderSync\CollectionFactory as OrderSyncCollectionFactory;
use Psr\Log\LoggerInterface;

/**
 * Observer for shipment tracking info updates
 * Syncs tracking numbers to SimplyIN when added to shipment
 */
class ShipmentTrackSaveAfter implements ObserverInterface
{
    private const XML_PATH_API_KEY = 'payment/simplyin_payment/api_key';

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

    /**
     * @var Encryption
     */
    private $encryption;

    /**
     * @var OrderSyncCollectionFactory
     */
    private $orderSyncCollectionFactory;

    /**
     * @var ScopeConfigInterface
     */
    private $scopeConfig;

    /**
     * @var \Magento\Framework\Encryption\EncryptorInterface
     */
    private $encryptor;

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

    /**
     * @param ApiClient $apiClient
     * @param Encryption $encryption
     * @param OrderSyncCollectionFactory $orderSyncCollectionFactory
     * @param ScopeConfigInterface $scopeConfig
     * @param \Magento\Framework\Encryption\EncryptorInterface $encryptor
     * @param LoggerInterface $logger
     */
    public function __construct(
        ApiClient $apiClient,
        Encryption $encryption,
        OrderSyncCollectionFactory $orderSyncCollectionFactory,
        ScopeConfigInterface $scopeConfig,
        \Magento\Framework\Encryption\EncryptorInterface $encryptor,
        LoggerInterface $logger
    ) {
        $this->apiClient = $apiClient;
        $this->encryption = $encryption;
        $this->orderSyncCollectionFactory = $orderSyncCollectionFactory;
        $this->scopeConfig = $scopeConfig;
        $this->encryptor = $encryptor;
        $this->logger = $logger;
    }

    /**
     * Execute observer
     *
     * @param Observer $observer
     * @return $this
     */
    public function execute(Observer $observer): static
    {
        try {
            /** @var Track $track */
            $track = $observer->getEvent()->getTrack();

            $order = $this->resolveOrderFromTrack($track);
            if (!$order) {
                return $this;
            }

            // Check if order exists in SimplyIN
            if (!$this->isOrderSyncedToSimplyIn((int)$order->getId())) {
                return $this;
            }

            $email = $this->getOrderEmail($order);
            if (empty($email)) {
                return $this;
            }

            // Get all tracking numbers for this order
            $trackingNumbers = $this->getAllTrackingNumbers($order);

            // Send encrypted update with tracking info
            $this->sendTrackingUpdate($order, $trackingNumbers, $email);

        } catch (\Exception $e) {
            $this->logger->error('SimplyIN: Shipment track observer error', [
                'error' => $e->getMessage()
            ]);
        }

        return $this;
    }

    /**
     * Resolve the order from the track event, applying processing guards
     *
     * @param Track|null $track
     * @return \Magento\Sales\Model\Order|null
     */
    private function resolveOrderFromTrack($track)
    {
        if (!$track || !$track->getId()) {
            return null;
        }

        // Only process newly created tracks (not updates to existing ones)
        if ($track->getOrigData('track_number') === $track->getTrackNumber()) {
            return null;
        }

        $shipment = $track->getShipment();
        if (!$shipment) {
            return null;
        }

        $order = $shipment->getOrder();
        if (!$order || !$order->getId()) {
            return null;
        }

        return $order;
    }

    /**
     * Get order email from various sources
     *
     * @param \Magento\Sales\Model\Order $order
     * @return string|null
     */
    private function getOrderEmail($order): ?string
    {
        $email = $order->getCustomerEmail();
        
        if (empty($email)) {
            $billingAddress = $order->getBillingAddress();
            if ($billingAddress) {
                $email = $billingAddress->getEmail();
            }
        }
        
        if (empty($email)) {
            $shippingAddress = $order->getShippingAddress();
            if ($shippingAddress) {
                $email = $shippingAddress->getEmail();
            }
        }

        return $email ?: null;
    }

    /**
     * Check if order is synced to SimplyIN
     *
     * @param int $orderId
     * @return bool
     */
    private function isOrderSyncedToSimplyIn(int $orderId): bool
    {
        $collection = $this->orderSyncCollectionFactory->create();
        $collection->addFieldToFilter('order_id', $orderId);

        return $collection->getSize() > 0;
    }

    /**
     * Get all tracking numbers from order in SimplyIN format
     *
     * Format: [{'number': 'xxx', 'provider': 'carrier'}]
     *
     * @param \Magento\Sales\Model\Order $order
     * @return array
     */
    private function getAllTrackingNumbers($order): array
    {
        $trackingNumbers = [];

        $shipmentsCollection = $order->getShipmentsCollection();
        if ($shipmentsCollection) {
            foreach ($shipmentsCollection as $shipment) {
                $tracks = $shipment->getAllTracks();
                foreach ($tracks as $track) {
                    $trackingNumbers[] = [
                        'number' => $track->getTrackNumber(),
                        'provider' => $track->getCarrierCode() ?: $track->getTitle()
                    ];
                }
            }
        }

        return $trackingNumbers;
    }

    /**
     * Get API key
     *
     * @return string|null
     */
    private function getApiKey(): ?string
    {
        $encryptedKey = $this->scopeConfig->getValue(
            self::XML_PATH_API_KEY,
            ScopeInterface::SCOPE_STORE
        );

        if ($encryptedKey) {
            return $this->encryptor->decrypt($encryptedKey);
        }

        return null;
    }

    /**
     * Send tracking update to SimplyIN
     *
     * @param \Magento\Sales\Model\Order $order
     * @param array $trackingNumbers
     * @param string $email
     * @return void
     */
    private function sendTrackingUpdate($order, array $trackingNumbers, string $email): void
    {
        $apiKey = $this->getApiKey();

        // Build payload matching WordPress plugin format
        $payload = [
            'email' => $email,
            'shopOrderNumber' => $order->getIncrementId(),  // Keep as string to preserve leading zeros
            'newOrderStatus' => $this->mapStatus($order->getStatus()),
            'apiKey' => $apiKey
        ];

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

        // Encrypt payload with JSON_UNESCAPED_SLASHES like PrestaShop
        $plaintext = json_encode($payload, JSON_UNESCAPED_SLASHES);
        $secretKey = $this->encryption->getSecretKey($email);
        $encryptedContent = $this->encryption->encrypt($plaintext, $secretKey);

        if ($encryptedContent === false) {
            $this->logger->error('SimplyIN: Failed to encrypt tracking payload', [
                'order_id' => $order->getId()
            ]);
            return;
        }

        // Hash email
        $hashedEmail = $this->encryption->hashEmail($email);

        // Send to API with plain payload for logging and email for decrypting response
        $response = $this->apiClient->saveEncryptedOrderStatusChange($encryptedContent, $hashedEmail, $plaintext, $email);

        if ($response['success']) {
            $this->logger->info('SimplyIN: Tracking info updated successfully', [
                'order_id' => $order->getId(),
                'tracking_count' => count($trackingNumbers)
            ]);
        } else {
            $this->logger->warning('SimplyIN: Failed to update tracking info', [
                'order_id' => $order->getId(),
                'error' => $response['error'] ?? 'Unknown error'
            ]);
        }
    }

    /**
     * Map Magento status to SimplyIN status
     *
     * SimplyIN expects statuses like: InTransit, Shipped, Delivered, completed, cancelled
     *
     * @param string $status
     * @return string
     */
    private function mapStatus(string $status): string
    {
        $statusMap = [
            // Completed/Delivered statuses
            'complete' => 'Delivered',
            'closed' => 'Delivered',
            
            // Shipped/In Transit statuses
            'shipped' => 'Shipped',
            'shipping' => 'Shipped',
            'in_transit' => 'InTransit',
            
            // Cancelled statuses
            'canceled' => 'cancelled',
            'cancelled' => 'cancelled',
            
            // Processing
            'processing' => 'Processing',
        ];

        return $statusMap[$status] ?? $status;
    }
}
