<?php

namespace Modules\WhatsApp\Providers;

use Illuminate\Support\ServiceProvider;
use Illuminate\Console\Scheduling\Schedule;
use Modules\WhatsApp\Entities\Services\TransportManager;

class WhatsAppServiceProvider extends ServiceProvider
{
    public function boot()
    {
        $this->registerConfig();
        $this->registerQueueConnection();
        $this->registerViews();
        $this->loadMigrationsFrom(__DIR__ . '/../Database/Migrations');
        $this->registerTranslations();
        $this->registerCommands();
        $this->registerSchedule();
        $this->registerObservers();
    }

    /**
     * Hook core ERP events into WhatsApp notifications. Guarded so it stays inert
     * until the module's tables exist (fresh install / pre-migration).
     */
    protected function registerObservers(): void
    {
        // Guarded so it stays inert until the module's tables exist (fresh install /
        // pre-migration). Wrapped because Schema::hasTable() itself throws when the
        // default DB connection is momentarily unreachable/misconfigured during some
        // boot contexts (e.g. a stale 'forge' default) — boot must never fatal on it.
        try {
            if (!\Schema::hasTable('wa_settings')) {
                return;
            }

            // Core sales lifecycle
            \App\Transaction::observe(\Modules\WhatsApp\Observers\TransactionObserver::class);
            \App\TransactionPayment::observe(\Modules\WhatsApp\Observers\TransactionPaymentObserver::class);

            // New customer welcome
            \App\Contact::observe(\Modules\WhatsApp\Observers\ContactObserver::class);

            // VetClinic appointments + pet/owner onboarding (only when present)
            if (class_exists(\Modules\VetClinic\Entities\VcAppointment::class) && \Schema::hasTable('vc_appointments')) {
                \Modules\VetClinic\Entities\VcAppointment::observe(\Modules\WhatsApp\Observers\VcAppointmentObserver::class);
            }
            if (class_exists(\Modules\VetClinic\Entities\VcPet::class) && \Schema::hasTable('vc_pets')) {
                \Modules\VetClinic\Entities\VcPet::observe(\Modules\WhatsApp\Observers\VcPetObserver::class);
            }
            if (class_exists(\Modules\VetClinic\Entities\VcPetOwnerDetail::class) && \Schema::hasTable('vc_pet_owner_details')) {
                \Modules\VetClinic\Entities\VcPetOwnerDetail::observe(\Modules\WhatsApp\Observers\VcPetOwnerDetailObserver::class);
            }

            // LabCore results (only when that module is present)
            if (class_exists(\Modules\LabCore\Entities\LabTestSession::class) && \Schema::hasTable('lab_test_sessions')) {
                \Modules\LabCore\Entities\LabTestSession::observe(\Modules\WhatsApp\Observers\LabTestSessionObserver::class);
            }
        } catch (\Throwable $e) {
            // DB unreachable at boot — skip observer wiring rather than 500 the request.
            return;
        }
    }

    public function register()
    {
        $this->app->register(RouteServiceProvider::class);

        // The transport manager resolves the right driver (meta|web) per channel.
        $this->app->singleton(TransportManager::class, function ($app) {
            return new TransportManager();
        });
    }

    protected function registerConfig()
    {
        $this->publishes([
            __DIR__ . '/../Config/config.php' => config_path('whatsapp.php'),
        ], 'config');
        $this->mergeConfigFrom(
            __DIR__ . '/../Config/config.php', 'whatsapp'
        );
    }

    /**
     * Pin WhatsApp jobs to their own database queue connection regardless of the
     * app-wide QUEUE_CONNECTION (which is 'sync' here). This is what lets a
     * persistent worker drain the throttled outbox without blocking web requests.
     */
    protected function registerQueueConnection()
    {
        $name = config('whatsapp.queue.connection', 'whatsapp_db');
        if (!config("queue.connections.$name")) {
            config([
                "queue.connections.$name" => [
                    'driver'        => 'database',
                    'table'         => 'jobs',
                    'queue'         => config('whatsapp.queue.queue', 'whatsapp'),
                    'retry_after'   => 600,
                    'after_commit'  => true,
                ],
            ]);
        }
    }

    public function registerViews()
    {
        $viewPath = resource_path('views/modules/WhatsApp');
        $sourcePath = __DIR__ . '/../Resources/views';

        $this->publishes([
            $sourcePath => $viewPath,
        ], 'views');

        $this->loadViewsFrom(array_merge(array_map(function ($path) {
            return $path . '/modules/whatsapp';
        }, \Config::get('view.paths')), [$sourcePath]), 'whatsapp');
    }

    public function registerTranslations()
    {
        $langPath = resource_path('lang/modules/WhatsApp');

        if (is_dir($langPath)) {
            $this->loadTranslationsFrom($langPath, 'whatsapp');
        } else {
            $this->loadTranslationsFrom(__DIR__ . '/../Resources/lang', 'whatsapp');
        }
    }

    protected function registerCommands()
    {
        if ($this->app->runningInConsole()) {
            $this->commands([
                \Modules\WhatsApp\Console\SweepPendingMessages::class,
                \Modules\WhatsApp\Console\MarkStaleChannelsOffline::class,
                \Modules\WhatsApp\Console\SendAppointmentReminders::class,
                \Modules\WhatsApp\Console\SendPaymentReminders::class,
                \Modules\WhatsApp\Console\SendVaccinationReminders::class,
                \Modules\WhatsApp\Console\SendPetBirthdays::class,
                \Modules\WhatsApp\Console\SendLowStockAlerts::class,
            ]);
        }
    }

    /**
     * Self-register the safety-net cron jobs (no need to touch the core
     * app/Console/Kernel). These are what guarantee a notification is never
     * lost across worker outages or QR disconnects.
     */
    protected function registerSchedule(): void
    {
        $this->callAfterResolving(Schedule::class, function (Schedule $schedule) {
            // Re-drive any due message still pending delivery.
            $schedule->command('whatsapp:sweep')->everyMinute()->withoutOverlapping();
            // Flag QR channels whose bridge heartbeat went stale.
            $schedule->command('whatsapp:health-check')->everyMinute()->withoutOverlapping();
            // Next-day appointment reminders (VetClinic).
            $schedule->command('whatsapp:appointment-reminders')->dailyAt('18:00');
            // Overdue invoice reminders.
            $schedule->command('whatsapp:payment-reminders')->dailyAt('09:00');
            // Vaccination-due reminders (VetClinic).
            $schedule->command('whatsapp:vaccination-reminders')->dailyAt('09:00');
            // Pet birthday greetings (VetClinic).
            $schedule->command('whatsapp:pet-birthdays')->dailyAt('08:00');
            // Daily low-stock summary to opted-in businesses.
            $schedule->command('whatsapp:low-stock-alerts')->dailyAt('08:00')->withoutOverlapping();
        });
    }

    public function provides()
    {
        return [];
    }
}
