<?php

namespace App\Services;

use App\Models\SmsConfiguration;
use Illuminate\Support\Facades\Cache;
use Illuminate\Support\Facades\Log;

/**
 * SmsConfigurationService
 *
 * Manages CRUD operations for Africa's Talking SMS credentials.
 */
class SmsConfigurationService
{
    protected string $cacheKey = 'sms_active_configuration';
    protected int $cacheTtl = 3600;

    public function getConfiguration(): ?SmsConfiguration
    {
        try {
            $dbConfig = Cache::remember($this->cacheKey, $this->cacheTtl, function () {
                return SmsConfiguration::getActive();
            });

            if ($dbConfig) {
                return $dbConfig;
            }

            // Fall back to environment variables when no DB record exists
            return $this->buildConfigFromEnv();

        } catch (\Exception $e) {
            Log::error('Failed to retrieve SMS configuration', [
                'error' => $e->getMessage(),
                'trace' => $e->getTraceAsString(),
            ]);
            return null;
        }
    }

    /**
     * Build a transient SmsConfiguration from environment variables.
     * The returned instance is NOT persisted to the database.
     *
     * @return SmsConfiguration|null
     */
    protected function buildConfigFromEnv(): ?SmsConfiguration
    {
        $username = env('AT_USERNAME');
        $apiKey   = env('AT_API_KEY');
        $senderId = env('AT_SENDER_ID');

        if (!$username || !$apiKey || !$senderId) {
            return null;
        }

        // Build a transient (unsaved) model so the rest of the stack works unchanged
        $config = new SmsConfiguration();
        $config->username    = $username;
        $config->api_key     = $apiKey;
        $config->sender_id   = $senderId;
        $config->environment = app()->environment('production') ? 'production' : 'sandbox';
        $config->is_active   = true;
        // id stays null — callers that use it for logging will just get null, which is fine

        return $config;
    }

    public function saveConfiguration(array $data): SmsConfiguration
    {
        try {
            \DB::beginTransaction();

            if (isset($data['is_active']) && $data['is_active']) {
                SmsConfiguration::query()->update(['is_active' => false]);
            }

            $existingConfig = SmsConfiguration::withTrashed()->first();

            if ($existingConfig) {
                if ($existingConfig->trashed()) {
                    $existingConfig->restore();
                }
                $existingConfig->update($data);
                $configuration = $existingConfig;
            } else {
                $configuration = SmsConfiguration::create($data);
            }

            $this->clearCache();

            \DB::commit();

            Log::info('SMS configuration saved successfully', [
                'environment' => $configuration->environment,
                'sender_id'   => $configuration->sender_id,
                'is_active'   => $configuration->is_active,
            ]);

            return $configuration;

        } catch (\Exception $e) {
            \DB::rollBack();

            Log::error('Failed to save SMS configuration', [
                'error' => $e->getMessage(),
                'data'  => array_merge($data, ['api_key' => '***hidden***']),
            ]);

            throw $e;
        }
    }

    public function deleteConfiguration(): bool
    {
        try {
            $configuration = $this->getConfiguration();

            if (!$configuration || !$configuration->exists) {
                return false;
            }

            $configuration->delete();
            $this->clearCache();

            Log::info('SMS configuration deleted');

            return true;

        } catch (\Exception $e) {
            Log::error('Failed to delete SMS configuration', [
                'error' => $e->getMessage(),
                'trace' => $e->getTraceAsString(),
            ]);
            throw $e;
        }
    }

    public function isConfigured(): bool
    {
        $configuration = $this->getConfiguration();
        return $configuration !== null && $configuration->is_active;
    }

    public function getStatus(): array
    {
        $configuration = $this->getConfiguration();

        if (!$configuration) {
            return [
                'configured'  => false,
                'environment' => null,
                'sender_id'   => null,
                'is_active'   => false,
            ];
        }

        return [
            'configured'  => true,
            'environment' => $configuration->environment,
            'sender_id'   => $configuration->sender_id,
            'is_active'   => $configuration->is_active,
            'updated_at'  => $configuration->updated_at?->format('Y-m-d H:i:s'),
        ];
    }

    public function clearCache(): void
    {
        Cache::forget($this->cacheKey);
    }
}
