<?php

/**
 * Copyright 2024-2025 Simply.IN Sp. z o.o.
 *
 * NOTICE OF LICENSE
 *
 * Licensed under the EUPL-1.2 or later.
 * You may not use this work except in compliance with the Licence.
 *
 * Copy of the Licence is available at:
 * https://joinup.ec.europa.eu/software/page/eupl
 * It is bundled with this package in the file LICENSE.txt
 *
 * Unless required by applicable law or agreed to in writing,
 * software distributed under the Licence is distributed on an as is basis,
 * without warranties or conditions of any kind, either express or implied.
 * Check the Licence for the specific language governing permissions
 * and limitations under the License.
 *
 * @author   Simply.IN Sp. z o.o.
 * @copyright 2024-2025 Simply.IN Sp. z o.o.
 * @license   https://joinup.ec.europa.eu/software/page/eupl
 */

declare(strict_types=1);

namespace SimplyIn\Payment;

use Cart;
use Configuration;
use Currency;
use Order;
use SimplyIn\Checkout\PaymentMethodDataBuilder;
use SimplyIn\Session\SimplyInSessionInterface;
use SimplyInOrder;

if (!defined('_PS_VERSION_')) {
    exit;
}

final class PaymentCreationService
{
    public function __construct(
        private readonly SimplyInSessionInterface $session,
        private readonly PaymentApiInterface $api,
        private readonly PaymentRecorderInterface $recorder,
        private readonly OrderStateUpdaterInterface $orderStateUpdater,
        private readonly PaymentMethodDataBuilder $paymentMethodDataBuilder,
    ) {
    }

    public function createPayment(
        Cart $cart,
        Order $order,
        string $customerFirstName,
        string $customerLastName,
        string $guestEmail,
        string $authenticatedEmail,
        bool $isGuest,
        bool $accountCreated,
        string $returnUrl,
        string $webhookUrl,
    ): PaymentCreationResult {
        $authToken = (string) ($this->session->get('simplyin_auth_token') ?: '');
        $paymentMethodId = $this->session->get('simplyin_payment_id');
        $paymentType = (string) ($this->session->get('simplyin_payment_type') ?: '');

        $paymentId = $this->recorder->newPaymentId($order);
        $email = $authToken !== '' ? $authenticatedEmail : $guestEmail;
        $paymentMethodData = $this->paymentMethodDataBuilder->build($paymentType, $accountCreated);

        // The backend's order _id is the canonical matching key for post-create ops. Persisted at
        // order creation in simplyin_order.simplyin_id (same source the status channel uses,
        // OrderStatusSync). Legacy orders have no stored _id -> omit orderId and let the backend
        // fall back to shopOrderNumber. Never send an empty orderId.
        $simplyInOrder = SimplyInOrder::getByReference((string) $order->reference);
        $simplyinOrderId = (string) ($simplyInOrder->simplyin_id ?? '');

        $body = [
            'paymentId' => $paymentId,
            'paymentMethodId' => $paymentMethodId,
            'title' => (string) $order->reference,
            'amount' => (float) $order->getOrdersTotalPaid(),
            'currency' => Currency::getIsoCodeById((int) $order->id_currency),
            'customerPaymentData' => [
                'email' => $email,
                'firstName' => $customerFirstName,
                'lastName' => $customerLastName,
                'phone' => '',
            ],
            'paymentMethodData' => $paymentMethodData,
            'returnUrl' => $returnUrl,
            'webhookUrl' => $webhookUrl,
        ];

        if ($simplyinOrderId !== '') {
            $body['orderId'] = $simplyinOrderId;
        }

        $response = $this->api->createPayment($body, $authToken);

        $status = $this->resolveStatus($response);

        $this->recorder->record(
            $cart,
            $paymentType,
            $status,
            $paymentId,
            (string) ($this->session->get('simplyin_payment_provider') ?: ''),
            (string) ($this->session->get('simplyin_card_provider') ?: ''),
            (string) ($this->session->get('simplyin_payment_image') ?: ''),
            (string) ($this->session->get('simplyin_payment_logo') ?: ''),
        );

        if ($status === 'FAILED') {
            $this->orderStateUpdater->update(
                $order,
                (int) Configuration::get('SIMPLYIN_PAYMENT_STATUS_CANCELED'),
                'markAsRejected',
            );
        }

        if ($isGuest) {
            $this->session->clear();
        }
        $this->session->clearCustomer();

        $externalRedirect = null;
        if (($paymentType === 'card' || $paymentType === 'add-card')
            && is_object($response)
            && isset($response->redirectUrl)
            && is_string($response->redirectUrl)
        ) {
            $externalRedirect = $response->redirectUrl;
        }

        return new PaymentCreationResult($status, $externalRedirect);
    }

    private function resolveStatus(?object $response): string
    {
        if ($response === null) {
            return 'FAILED';
        }
        if (isset($response->code) && $response->code === 'FORBIDDEN') {
            return 'FAILED';
        }
        if (isset($response->status) && is_string($response->status)) {
            return $response->status;
        }

        return 'FAILED';
    }
}
