<?php
/**
 * BookiFlex Payment Extension
 *
 * @package    BookiFlex
 * @subpackage Payment
 * @author     BookiFlex
 * @copyright  Copyright (c) 2025 BookiFlex
 * @license    GPL-2.0-or-later
 *
 * @link       https://bookiflex.com
 */

declare(strict_types=1);

 namespace BookiFlex\Extensions\Payment;

use BookiFlex\Core\Contract\Payment\PaymentAllocationProviderInterface;
use BookiFlex\Core\Contract\Payment\PaymentFactoryInterface;
use BookiFlex\Core\Contract\Payment\PaymentGatewayManagerInterface;
use BookiFlex\Extensions\Payment\Contract\PaymentInitiatorInterface;
use BookiFlex\Extensions\Payment\Api\Controller\PaymentCallbackController;
use BookiFlex\Extensions\Payment\Api\Controller\PaymentController;
use BookiFlex\Extensions\Payment\Infrastructure\Payum\CycleStorage;
use BookiFlex\Extensions\Payment\Model\PaymentAllocation;
use BookiFlex\Extensions\Payment\Model\PaymentToken;
use BookiFlex\Extensions\Payment\Provider\PaymentAllocationProvider;
use BookiFlex\Extensions\Payment\Provider\PaymentProvider;
use BookiFlex\Extensions\Payment\Repository\PaymentAllocationRepository;
use BookiFlex\Extensions\Payment\Repository\PaymentRepository;
use BookiFlex\Extensions\Payment\Service\PaymentFactory;
use BookiFlex\Extensions\Payment\Service\PaymentGatewayManager;
use BookiFlex\Extensions\Payment\Service\PaymentManager;
use BookiFlex\Extensions\Payment\Service\SyncPaymentStatusWithGateway;
use BookiFlex\Extensions\Payment\Service\PaymentInitiator;
use BookiFlex\Extensions\Payment\Service\Processor\PaymentProcessorResolver;
use BookiFlex\Extensions\Payment\Service\Processor\PayumPaymentProcessor;
use BookiFlex\Core\Repository\ReservationRepository;
use BookiFlex\Core\Service\Reservation\ReservationStatusManager;
use Cycle\ORM\EntityManagerInterface;
use Cycle\ORM\ORM;
use Payum\Core\Payum;
use Pimple\Container;
use Pimple\ServiceProviderInterface;

defined( 'ABSPATH' ) || exit;

class ServiceProvider implements ServiceProviderInterface
{
    public function register(Container $pimple): void
    {
        // Storages
        $pimple['payum.storage'] = function ($c) {
            return new CycleStorage(
                $c->get(EntityManagerInterface::class),
                $c->get(ORM::class),
                Model\Payment::class
            );
        };

        $pimple['payum.token.storage'] = function ($c) {
            return new CycleStorage(
                $c->get(EntityManagerInterface::class),
                $c->get(ORM::class),
                PaymentToken::class
            );
        };

        $pimple[PaymentGatewayManagerInterface::class] = function () {
            return new PaymentGatewayManager();
        };

        $pimple[Payum::class] = function ($c) {
            /** @var PaymentGatewayManager $paymentGatewayManager */
            $paymentGatewayManager        = $c->get(PaymentGatewayManagerInterface::class);
            $paymentStorage = $c->get('payum.storage');
            $tokenStorage   = $c->get('payum.token.storage');

            return $paymentGatewayManager->makePayum($paymentStorage, $tokenStorage);
        };

        $pimple[PaymentFactoryInterface::class] = function () {
            return new PaymentFactory();
        };

        // Payment processors (initiation seam): Payum is the default catch-all.
        // Other extensions (e.g. WooCommerce) add their processor via
        // PaymentProcessorResolver::addProcessor().
        $pimple[PayumPaymentProcessor::class] = function ($c) {
            return new PayumPaymentProcessor(
                $c->get(Payum::class)
            );
        };

        $pimple[PaymentProcessorResolver::class] = function ($c) {
            return new PaymentProcessorResolver(
                $c->get(PayumPaymentProcessor::class)
            );
        };

        $pimple[PaymentInitiatorInterface::class] = function ($c) {
            return new PaymentInitiator(
                $c->get(ReservationRepository::class),
                $c->get(PaymentAllocationProviderInterface::class),
                $c->get(Payum::class),
                $c->get(PaymentProcessorResolver::class)
            );
        };

        $pimple[PaymentAllocationProviderInterface::class] = function ($c) {
            return new PaymentAllocationProvider(
                $c->get(PaymentAllocationRepository::class)
            );
        };

        // Services
        $pimple[PaymentFactory::class] = function () {
            return new PaymentFactory();
        };

        $pimple[PaymentInitiator::class] = function ($c) {
            return new PaymentInitiator(
                $c->get(ReservationRepository::class),
                $c->get(PaymentAllocationProviderInterface::class),
                $c->get(Payum::class),
                $c->get(PaymentProcessorResolver::class),
            );
        };

        $pimple[PaymentProvider::class] = function ($c) {
            return new PaymentProvider(
                $c->get(Repository\PaymentRepository::class)
            );
        };

        $pimple[SyncPaymentStatusWithGateway::class] = function ($c) {
            return new SyncPaymentStatusWithGateway(
                $c->get(Payum::class),
                $c->get(ReservationStatusManager::class),
                $c->get('config')
            );
        };

        $pimple[PaymentManager::class] = function ($c) {
            return new PaymentManager(
                $c->get(Payum::class),
                $c->get(SyncPaymentStatusWithGateway::class),
                $c->get('payment.logger'),
            );
        };

        $pimple[Service\PaymentListService::class] = function ($c) {
            return new Service\PaymentListService(
                $c->get(Repository\PaymentRepository::class),
                $c->get(Repository\PaymentAllocationRepository::class)
            );
        };

        // Controllers
        $pimple[PaymentController::class] = function ($c) {
            return new PaymentController(
                $c->get(PaymentProvider::class),
                $c->get(PaymentManager::class),
                $c->get(PaymentInitiator::class)
            );
        };

        $pimple[PaymentCallbackController::class] = function ($c) {
            return new PaymentCallbackController(
                $c->get(PaymentManager::class)
            );
        };

        // Repositories
        $pimple[PaymentRepository::class] = function ($c) {
            $repository = $c->get(ORM::class)->getRepository(Model\Payment::class);
	        $repository->setEntityManager($c->get(EntityManagerInterface::class));
	        return $repository;
        };
        $pimple[PaymentAllocationRepository::class] = function ($c) {
            return $c->get(ORM::class)->getRepository(PaymentAllocation::class);
        };

        // Logger
        $pimple['payment.logger'] = function ($c) {
            return null;
//            $logger = $c->get(LoggerInterface::class);
//            $logger->setChannel('payment');
//            return $logger;
        };
    }
}
