<?php
namespace Bookaro\Service;

defined( 'ABSPATH' ) || exit;

use Bookaro\Contracts\CalendarSyncInterface;
use Bookaro\Contracts\MessagingGatewayInterface;
use Bookaro\Contracts\PaymentsGatewayInterface;
use Bookaro\Contracts\WebhookDispatcherInterface;
use Bookaro\Contracts\ReportsProviderInterface;
use Bookaro\Contracts\ExportsProviderInterface;
use Bookaro\Repository\BookingRepository;

/**
 * Centralized service resolver for optional/pro integrations.
 */
class ServiceLocator
{
    private ?BookingRepository $db = null;
    private array $instances = [];

    public function set_repository( BookingRepository $db ): void
    {
        $this->db = $db;
    }

    public function payments( ?BookingRepository $db = null ): PaymentsGatewayInterface
    {
        return $this->resolve(
            'payments',
            $db,
            new NullPaymentsGateway(),
            PaymentsGatewayInterface::class,
            'bookaro_payments_service',
            'bookaro_payments_gateway'
        );
    }

    public function calendar( ?BookingRepository $db = null ): CalendarSyncInterface
    {
        return $this->resolve(
            'calendar',
            $db,
            new NullCalendarSync(),
            CalendarSyncInterface::class,
            'bookaro_calendar_service',
            null
        );
    }

    public function messaging( ?BookingRepository $db = null ): MessagingGatewayInterface
    {
        return $this->resolve(
            'messaging',
            $db,
            new NullMessagingGateway(),
            MessagingGatewayInterface::class,
            'bookaro_messaging_service',
            'bookaro_message_gateway'
        );
    }

    public function webhooks( ?BookingRepository $db = null ): WebhookDispatcherInterface
    {
        return $this->resolve(
            'webhooks',
            $db,
            new NullWebhookDispatcher(),
            WebhookDispatcherInterface::class,
            'bookaro_webhooks_service',
            'bookaro_webhook_dispatcher'
        );
    }

    public function reports( ?BookingRepository $db = null ): ReportsProviderInterface
    {
        return $this->resolve(
            'reports',
            $db,
            new NullReportsProvider(),
            ReportsProviderInterface::class,
            'bookaro_reports_service',
            'bookaro_reports_provider'
        );
    }

    public function exports( ?BookingRepository $db = null ): ExportsProviderInterface
    {
        return $this->resolve(
            'exports',
            $db,
            new NullExportsProvider(),
            ExportsProviderInterface::class,
            'bookaro_exports_service',
            'bookaro_exports_provider'
        );
    }

    public function set_payments( PaymentsGatewayInterface $service ): void
    {
        $this->instances['payments'] = $service;
    }

    public function set_calendar( CalendarSyncInterface $service ): void
    {
        $this->instances['calendar'] = $service;
    }

    public function set_messaging( MessagingGatewayInterface $service ): void
    {
        $this->instances['messaging'] = $service;
    }

    public function set_webhooks( WebhookDispatcherInterface $service ): void
    {
        $this->instances['webhooks'] = $service;
    }

    public function set_reports( ReportsProviderInterface $service ): void
    {
        $this->instances['reports'] = $service;
    }

    public function set_exports( ExportsProviderInterface $service ): void
    {
        $this->instances['exports'] = $service;
    }

    private function resolve(
        string $key,
        ?BookingRepository $db,
        $default,
        string $interface,
        string $filter,
        ?string $legacy_filter
    ) {
        if ( isset( $this->instances[ $key ] ) ) {
            return $this->instances[ $key ];
        }

        $repo = $db ?? $this->db;
        $service = $default;

        if ( function_exists( 'apply_filters' ) ) {
            // phpcs:ignore WordPress.NamingConventions.PrefixAllGlobals.DynamicHooknameFound
            $service = apply_filters( $filter, $service, $repo );
            if ( $legacy_filter ) {
                // phpcs:ignore WordPress.NamingConventions.PrefixAllGlobals.DynamicHooknameFound
                $service = apply_filters( $legacy_filter, $service, $repo );
            }
        }

        if ( ! $service instanceof $interface ) {
            $service = $default;
        }

        $this->instances[ $key ] = $service;
        return $service;
    }
}
