<?php

namespace Config;

use App\Libraries\BackupService;
use App\Libraries\ClaudeService;
use App\Libraries\ConciergeService;
use App\Libraries\DailyBriefingService;
use App\Libraries\EmailService;
use App\Libraries\HubtelService;
use App\Libraries\MessagingService;
use App\Libraries\PdfService;
use App\Libraries\PlatformSettings;
use App\Libraries\Settings;
use App\Libraries\TenantContext;
use App\Libraries\TenantProvisioner;
use App\Libraries\WhatsAppService;
use App\Models\AiCallLogModel;
use App\Models\Control\PlatformSettingModel;
use App\Models\MessageLogModel;
use App\Models\TenantSettingModel;
use CodeIgniter\Config\BaseService;
use CodeIgniter\Database\ConnectionInterface;

/**
 * Services Configuration file.
 *
 * Services are simply other classes/libraries that the system uses
 * to do its job. This is used by CodeIgniter to allow the core of the
 * framework to be swapped out easily without affecting the usage within
 * the rest of your application.
 *
 * This file holds any application-specific services, or service overrides
 * that you might need. An example has been included with the general
 * method format you should use for your service methods. For more examples,
 * see the core Services file at system/Config/Services.php.
 */
class Services extends BaseService
{
    /*
     * public static function example($getShared = true)
     * {
     *     if ($getShared) {
     *         return static::getSharedInstance('example');
     *     }
     *
     *     return new \CodeIgniter\Example();
     * }
     */

    /**
     * Per-request holder for the resolved tenant + its DB connection.
     * Always shared: there must only ever be one "current tenant" per request.
     */
    public static function tenantContext(bool $getShared = true): TenantContext
    {
        if ($getShared) {
            return static::getSharedInstance('tenantContext');
        }

        return new TenantContext(config('Tenancy'));
    }

    /**
     * The current tenant's database connection. This is what TenantModel
     * (and anything else tenant-scoped) should ask for — callers never
     * need to know a tenant is even involved.
     */
    public static function tenantDb(bool $getShared = true): ConnectionInterface
    {
        return static::tenantContext($getShared)->getConnection();
    }

    /**
     * Not shared: provisioning is a one-shot CLI operation, never something
     * that should persist state across calls within a request.
     */
    public static function tenantProvisioner(bool $getShared = true): TenantProvisioner
    {
        if ($getShared) {
            return static::getSharedInstance('tenantProvisioner');
        }

        return new TenantProvisioner(config('Tenancy'), static::tenantContext());
    }

    /**
     * Per-tenant settings (Hubtel/WhatsApp/SMS credentials, channel
     * preferences, ...). Shared per request like everything tenant-scoped.
     */
    public static function settings(bool $getShared = true): Settings
    {
        if ($getShared) {
            return static::getSharedInstance('settings');
        }

        return new Settings(new TenantSettingModel(), service('encrypter'));
    }

    public static function hubtelService(bool $getShared = true): HubtelService
    {
        if ($getShared) {
            return static::getSharedInstance('hubtelService');
        }

        return new HubtelService(static::settings(), service('curlrequest'));
    }

    /**
     * Platform-level config (Hubtel account for collecting subscription
     * payments FROM hotels) — see App\Libraries\PlatformSettings for why
     * this is a separate credential store from the per-tenant one above.
     */
    public static function platformSettings(bool $getShared = true): PlatformSettings
    {
        if ($getShared) {
            return static::getSharedInstance('platformSettings');
        }

        return new PlatformSettings(new PlatformSettingModel(), service('encrypter'));
    }

    /**
     * Same HubtelService class as hubtelService() above, just handed the
     * platform's own credentials instead of a tenant's — used by
     * Admin\InvoiceController to collect subscription payments.
     */
    public static function platformHubtelService(bool $getShared = true): HubtelService
    {
        if ($getShared) {
            return static::getSharedInstance('platformHubtelService');
        }

        return new HubtelService(static::platformSettings(), service('curlrequest'));
    }

    public static function emailService(bool $getShared = true): EmailService
    {
        if ($getShared) {
            return static::getSharedInstance('emailService');
        }

        return new EmailService(static::settings());
    }

    public static function whatsAppService(bool $getShared = true): WhatsAppService
    {
        if ($getShared) {
            return static::getSharedInstance('whatsAppService');
        }

        return new WhatsAppService(static::settings(), service('curlrequest'));
    }

    public static function messagingService(bool $getShared = true): MessagingService
    {
        if ($getShared) {
            return static::getSharedInstance('messagingService');
        }

        return new MessagingService(static::settings(), static::hubtelService(), static::whatsAppService(), new MessageLogModel());
    }

    /**
     * The single entry point for every Claude API call — see
     * ClaudeService's own class doc comment for why every AI feature
     * calls this rather than hitting the Anthropic API directly.
     */
    public static function claudeService(bool $getShared = true): ClaudeService
    {
        if ($getShared) {
            return static::getSharedInstance('claudeService');
        }

        return new ClaudeService(static::settings(), service('curlrequest'), new AiCallLogModel());
    }

    /** Shared by the ai:daily-briefing command and the Dashboard's "Generate Briefing" button — see its own class doc comment. */
    public static function dailyBriefingService(bool $getShared = true): DailyBriefingService
    {
        if ($getShared) {
            return static::getSharedInstance('dailyBriefingService');
        }

        return new DailyBriefingService(static::claudeService());
    }

    /** Powers the WhatsApp Concierge — see ConciergeService's own class doc comment. */
    public static function conciergeService(bool $getShared = true): ConciergeService
    {
        if ($getShared) {
            return static::getSharedInstance('conciergeService');
        }

        return new ConciergeService(static::claudeService(), static::whatsAppService());
    }

    /** Powers scheduled/manual full-database backups — see BackupService's own class doc comment. */
    public static function backupService(bool $getShared = true): BackupService
    {
        if ($getShared) {
            return static::getSharedInstance('backupService');
        }

        return new BackupService(static::settings());
    }

    public static function pdfService(bool $getShared = true): PdfService
    {
        if ($getShared) {
            return static::getSharedInstance('pdfService');
        }

        return new PdfService();
    }
}
