<?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\Api\OrderRepositoryInterface;
use Simplyin\Payment\Helper\ApiClient;
use Psr\Log\LoggerInterface;
use Magento\Framework\App\RequestInterface;
use Magento\Framework\Serialize\Serializer\Json;

/**
 * Create SimplyIN account on any order observer
 *
 * Creates SimplyIN account when user opts in during checkout with any payment method
 */
class CreateSimplyinAccountOnAnyOrder implements ObserverInterface
{
    /**
     * @var OrderRepositoryInterface
     */
    protected $orderRepository;

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

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

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

    /**
     * @var Json
     */
    protected $json;

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

    /**
     * Execute observer
     *
     * Creates SimplyIN account if user opted in during checkout
     *
     * @param Observer $observer
     * @return void
     */
    public function execute(Observer $observer): void
    {
        try {
            /** @var \Magento\Sales\Model\Order $order */
            $order = $this->resolveOrder($observer);

            if (!$order || !$order->getId()) {
                $this->logger->debug('SimplyIN: No order found in observer', [
                    'event_name' => $observer->getEvent()->getName(),
                    'event_data' => array_keys($observer->getEvent()->getData())
                ]);
                return;
            }

            $this->logger->info('SimplyIN: Order found - #' . $order->getIncrementId());

            // Skip if this is a SimplyIN payment - it handles its own account creation
            $payment = $order->getPayment();
            if ($payment && $payment->getMethod() === 'simplyin_payment') {
                $this->logger->debug('SimplyIN: Skipping - SimplyIN payment method handles its own account creation');
                return;
            }

            // Check if user opted in for SimplyIN account creation
            // This data is passed from the frontend via additional data
            $optIn = $this->resolveOptInContext($payment, $order);
            $createAccount = $optIn['createAccount'];
            $phoneNumber = $optIn['phoneNumber'];

            if (!$createAccount) {
                $this->logger->debug('SimplyIN: User did not opt in for account creation on order #' . $order->getIncrementId());
                return;
            }

            $this->logger->info('SimplyIN: Creating account for order #' . $order->getIncrementId());

            // Get customer data from order
            $billingAddress = $order->getBillingAddress();
            $email = $order->getCustomerEmail();


            if (!$email) {
                $this->logger->warning('SimplyIN: No email found for order #' . $order->getIncrementId());
                return;
            }

            $accountData = $this->buildAccountData($email, $billingAddress, $phoneNumber);

            $this->logger->info('SimplyIN: Account data prepared', $accountData);

            // Create account via API
            $response = $this->apiClient->createAccount(
                $accountData['email'],
                $accountData['firstName'],
                $accountData['lastName'],
                $accountData['phone']
            );

            $this->handleApiResponse($response, $order, $payment, $email);

        } catch (\Exception $e) {
            $this->logger->error('SimplyIN CreateAccountOnAnyOrder Error: ' . $e->getMessage(), [
                'trace' => $e->getTraceAsString()
            ]);
        }
    }

    /**
     * Fetch payment additional data, log it, and resolve the account opt-in.
     *
     * @param \Magento\Sales\Api\Data\OrderPaymentInterface|null $payment
     * @param \Magento\Sales\Model\Order $order
     * @return array{createAccount: bool, phoneNumber: mixed}
     */
    private function resolveOptInContext($payment, $order): array
    {
        $additionalData = $payment ? $payment->getAdditionalInformation() : [];

        // Log only the field names, never the values — additional_data can carry PII
        // (e.g. simplyin_phone_number) that must not land in logs.
        $this->logger->debug('SimplyIN: Observer triggered for order #' . $order->getIncrementId(), [
            'payment_method' => $payment ? $payment->getMethod() : 'none',
            'additional_data_keys' => array_keys((array)$additionalData)
        ]);

        $optIn = $this->resolveAccountOptIn($additionalData);

        return [
            'createAccount' => $optIn['createAccount'],
            'phoneNumber' => $optIn['phoneNumber'],
        ];
    }

    /**
     * Resolve the order from the event using the supported fallbacks
     *
     * @param Observer $observer
     * @return \Magento\Sales\Model\Order|null
     */
    private function resolveOrder(Observer $observer)
    {
        /** @var \Magento\Sales\Model\Order $order */
        $order = $observer->getEvent()->getOrder();

        // Try different ways to get the order from the event
        if (!$order) {
            $order = $observer->getEvent()->getData('order');
        }

        // For checkout_submit_all_after event, order might be in 'orders' array
        if (!$order) {
            $orders = $observer->getEvent()->getOrders();
            if ($orders && is_array($orders) && count($orders) > 0) {
                $order = reset($orders);
            }
        }

        return $order;
    }

    /**
     * Resolve the account creation opt-in flag and phone number
     *
     * @param array $additionalData
     * @return array
     */
    private function resolveAccountOptIn($additionalData): array
    {
        $createAccount = false;
        $phoneNumber = null;

        // Check for account creation flag in payment additional data
        if (isset($additionalData['simplyin_create_account']) && $additionalData['simplyin_create_account']) {
            $createAccount = true;
            $phoneNumber = $additionalData['simplyin_phone_number'] ?? null;
        }

        return ['createAccount' => $createAccount, 'phoneNumber' => $phoneNumber];
    }

    /**
     * Prepare account data payload from order customer data
     *
     * @param string $email
     * @param mixed $billingAddress
     * @param string|null $phoneNumber
     * @return array
     */
    private function buildAccountData($email, $billingAddress, $phoneNumber): array
    {
        // Prepare account data
        return [
            'email' => $email,
            'firstName' => $billingAddress ? $billingAddress->getFirstname() : 'Customer',
            'lastName' => $billingAddress ? $billingAddress->getLastname() : 'User',
            'phone' => $phoneNumber ?: '+48000000000'
        ];
    }

    /**
     * Handle the API response: log result and persist auth token
     *
     * @param array $response
     * @param \Magento\Sales\Model\Order $order
     * @param mixed $payment
     * @param string $email
     * @return void
     */
    private function handleApiResponse($response, $order, $payment, $email): void
    {
        if ($response['success']) {
            $this->logger->info('SimplyIN: Account created successfully for ' . $email, [
                'order_id' => $order->getIncrementId()
            ]);

            // Store auth token if returned
            if (isset($response['data']['authToken'])) {
                $payment->setAdditionalInformation('simplyin_auth_token', $response['data']['authToken']);
                $this->orderRepository->save($order);
            }
        } else {
            $this->logger->warning('SimplyIN: Failed to create account for ' . $email, [
                'error' => $response['error'] ?? 'Unknown error',
                'order_id' => $order->getIncrementId()
            ]);
        }
    }
}
