<?php

namespace App\Providers;

use App\Facades\Feature;
use App\Facades\Settings;
use App\MeilisearchFilter;
use App\Modules\Stock\Motordat;
use App\Modules\Stock\Motors;
use App\Newsletter\CampaignMonitor;
use App\Newsletter\MailChimp;
use App\Services\Geolocation\CachedGeolocationResolver;
use App\Services\Geolocation\Contracts\GeolocationResolver;
use App\Services\Geolocation\IpApiGeolocationResolver;
use App\Services\Geolocation\NullGeolocationResolver;
use App\SettingRepository;
use App\SiteRepository;
use DrewM\MailChimp\MailChimp as MailChimpService;
use Illuminate\Contracts\Cache\Factory as CacheFactory;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Http\Client\Factory as HttpFactory;
use Illuminate\Support\Facades\Config;
use Illuminate\Support\ServiceProvider;
use Illuminate\Database\Eloquent\Relations\Relation;
use Laravel\Telescope\TelescopeApplicationServiceProvider;
use Mtc\MercuryDataModels\BodyStyleType;
use Mtc\MercuryDataModels\DrivetrainType;
use Mtc\MercuryDataModels\FuelType;
use Mtc\MercuryDataModels\KeyloopLeaseVehicleVariant;
use Mtc\MercuryDataModels\Repositories\FeatureRepository;
use Mtc\MercuryDataModels\Setting;
use Mtc\MercuryDataModels\TransmissionType;
use Mtc\MercuryDataModels\VehicleMake;
use Mtc\MercuryDataModels\VehicleModel;

class AppServiceProvider extends ServiceProvider
{
    /**
     * Register any application services.
     *
     * @return void
     */
    #[\Override]
    public function register()
    {
        if ($this->app->runningUnitTests()) {
            $this->setMigrationLocation();
        }

        if (class_exists(TelescopeApplicationServiceProvider::class)) {
            $this->app->register(TelescopeServiceProvider::class);
        }
    }

    /**
     * Bootstrap any application services.
     *
     * @return void
     */
    public function boot()
    {
        $this->bindNewsletterDrivers();
        $this->app->bind('site-settings', SettingRepository::class);
        $this->app->bind('feature-flags', FeatureRepository::class);
        $this->app->bind('motordat', Motordat::class);
        $this->app->bind('Motors', Motors::class);
        $this->app->bind('site-repository', SiteRepository::class);
        $this->app->bind('offer-filter', Config::get('filter.offer_filter_instance'));
        $this->app->bind('stock-and-offer-filter', Config::get('filter.stock_and_offer_filter_instance'));
        $this->app->bind('lease-vehicle-filter', Config::get('filter.lease_vehicle_filter_instance'));

        $this->bindMeilisearchFilter();
        $this->bindGeolocationResolver();

        Relation::morphMap([
            'make' => VehicleMake::class,
            'model' => VehicleModel::class,
            'fuel_type' => FuelType::class,
            'transmission' => TransmissionType::class,
            'body_type' => BodyStyleType::class,
            'drivetrain' => DrivetrainType::class,
            'setting' => Setting::class,
            'lease-vehicle' => KeyloopLeaseVehicleVariant::class,
        ]);

        //        Model::preventLazyLoading($this->app->environment('local'));
    }

    /**
     * Set up bindings for newsletter drivers
     *
     * @return void
     */
    private function bindNewsletterDrivers()
    {
        $this->app->bind(
            MailChimp::class,
            fn () => new MailChimp(new MailChimpService(Settings::get('newsletters-mailchimp-api_key')))
        );
        $this->app->bind(CampaignMonitor::class, fn () => new CampaignMonitor(new \CS_REST_Subscribers(
            Settings::get('newsletters-campaign-monitor-list_id'),
            ['api_key' => Settings::get('newsletters-campaign-monitor-api_key')]
        )));
    }

    /**
     * Due to the shared data models migrations are moved in mtcmedia/mercury-data-models
     *
     * @return void
     */
    private function setMigrationLocation()
    {
        $this->app->useDatabasePath($this->app->basePath('vendor/mtcmedia/mercury-data-models/database'));
        Config::set(
            'tenancy.migration_parameters.--path',
            $this->app->basePath('vendor/mtcmedia/mercury-data-models/database/migrations/tenant')
        );
    }

    private function bindGeolocationResolver(): void
    {
        $this->app->bind(GeolocationResolver::class, function ($app): GeolocationResolver {
            $driver = Config::get('geolocation.driver');
            $ttl = (int) Config::get('geolocation.cache_ttl', 86400);
            $cache = $app->make(CacheFactory::class)->store();

            $inner = match ($driver) {
                'ip-api' => new IpApiGeolocationResolver(
                    $app->make(HttpFactory::class),
                    (string) Config::get('geolocation.drivers.ip-api.endpoint'),
                    (int) Config::get('geolocation.drivers.ip-api.timeout', 2)
                ),
                default => new NullGeolocationResolver(),
            };

            return new CachedGeolocationResolver($inner, $cache, $ttl);
        });
    }

    /**
     * Conditionally bind MeilisearchFilter when feature is enabled.
     * This overrides the default filter binding when meilisearch-vehicle-filter feature is active.
     */
    private function bindMeilisearchFilter(): void
    {
        $this->app->bind('product-filter', function ($app) {
            if (Feature::isEnabled('meilisearch-vehicle-filter')) {
                return $app->make(MeilisearchFilter::class);
            }

            return $app->make(Config::get('filter.filter_instance'));
        });
    }
}
