<?php

namespace App\Models;

use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\SoftDeletes;
use Illuminate\Database\Eloquent\Relations\HasMany;

/**
 * SmsConfiguration Model
 * 
 * Stores and manages Africa's Talking API credentials with encryption at rest.
 * This model handles the secure storage of sensitive API credentials used for
 * sending SMS messages through Africa's Talking API.
 * 
 * Security Features:
 * - API key and username are encrypted using Laravel's encryption
 * - Soft deletes preserve configuration history
 * - Only one active configuration is allowed at a time
 * 
 * @property int $id
 * @property string $api_key Encrypted Africa's Talking API key
 * @property string $username Encrypted Africa's Talking username
 * @property string $sender_id Sender ID for outgoing SMS (max 11 chars)
 * @property string $environment API environment (sandbox/production)
 * @property bool $is_active Whether this configuration is active
 * @property \Illuminate\Support\Carbon|null $created_at
 * @property \Illuminate\Support\Carbon|null $updated_at
 * @property \Illuminate\Support\Carbon|null $deleted_at
 * 
 * @property-read \Illuminate\Database\Eloquent\Collection|\App\Models\SmsLog[] $logs
 */
class SmsConfiguration extends Model
{
    use HasFactory, SoftDeletes;

    /**
     * The table associated with the model.
     *
     * @var string
     */
    protected $table = 'sms_configurations';

    /**
     * The attributes that are mass assignable.
     *
     * @var array<int, string>
     */
    protected $fillable = [
        'api_key',
        'username',
        'sender_id',
        'environment',
        'is_active',
    ];

    /**
     * The attributes that should be hidden for serialization.
     * API key is never exposed in API responses or JSON.
     *
     * @var array<int, string>
     */
    protected $hidden = [
        'api_key',
    ];

    /**
     * The attributes that should be cast.
     * 
     * Encrypted casting ensures api_key and username are automatically
     * encrypted when stored and decrypted when retrieved.
     *
     * @var array<string, string>
     */
    protected $casts = [
        'api_key' => 'encrypted',
        'username' => 'encrypted',
        'is_active' => 'boolean',
        'environment' => 'string',
        'created_at' => 'datetime',
        'updated_at' => 'datetime',
        'deleted_at' => 'datetime',
    ];

    /**
     * Validation rules for SMS configuration.
     * Used by form requests and can be reused elsewhere.
     *
     * @var array<string, string>
     */
    public static array $validationRules = [
        'api_key' => 'required|string|min:10|max:500',
        'username' => 'required|string|min:3|max:191',
        'sender_id' => 'required|string|min:3|max:11|regex:/^[a-zA-Z0-9]+$/',
        'environment' => 'required|in:sandbox,production',
        'is_active' => 'boolean',
    ];

    /**
     * Custom validation messages.
     *
     * @var array<string, string>
     */
    public static array $validationMessages = [
        'api_key.required' => 'The API key is required.',
        'api_key.min' => 'The API key must be at least 10 characters.',
        'username.required' => 'The username is required.',
        'username.min' => 'The username must be at least 3 characters.',
        'sender_id.required' => 'The sender ID is required.',
        'sender_id.max' => 'The sender ID cannot exceed 11 characters.',
        'sender_id.regex' => 'The sender ID must contain only alphanumeric characters.',
        'environment.required' => 'Please select an environment.',
        'environment.in' => 'Environment must be either sandbox or production.',
    ];

    /**
     * Get the SMS logs associated with this configuration.
     *
     * @return \Illuminate\Database\Eloquent\Relations\HasMany
     */
    public function logs(): HasMany
    {
        return $this->hasMany(SmsLog::class, 'sms_configuration_id');
    }

    /**
     * Scope to get only active configurations.
     *
     * @param \Illuminate\Database\Eloquent\Builder $query
     * @return \Illuminate\Database\Eloquent\Builder
     */
    public function scopeActive($query)
    {
        return $query->where('is_active', true);
    }

    /**
     * Scope to get only production configurations.
     *
     * @param \Illuminate\Database\Eloquent\Builder $query
     * @return \Illuminate\Database\Eloquent\Builder
     */
    public function scopeProduction($query)
    {
        return $query->where('environment', 'production');
    }

    /**
     * Scope to get only sandbox configurations.
     *
     * @param \Illuminate\Database\Eloquent\Builder $query
     * @return \Illuminate\Database\Eloquent\Builder
     */
    public function scopeSandbox($query)
    {
        return $query->where('environment', 'sandbox');
    }

    /**
     * Get the current active configuration.
     * Returns the most recent active configuration.
     *
     * @return self|null
     */
    public static function getActive(): ?self
    {
        return static::active()
            ->latest()
            ->first();
    }

    /**
     * Check if there is an active configuration.
     *
     * @return bool
     */
    public static function hasActive(): bool
    {
        return static::active()->exists();
    }

    /**
     * Deactivate all other configurations when activating this one.
     * Ensures only one configuration is active at a time.
     *
     * @return void
     */
    public function activate(): void
    {
        // Deactivate all other configurations
        static::where('id', '!=', $this->id)
            ->update(['is_active' => false]);
        
        // Activate this configuration
        $this->update(['is_active' => true]);
    }

    /**
     * Get the API URL based on environment.
     *
     * @return string
     */
    public function getApiUrl(): string
    {
        return $this->environment === 'production'
            ? 'https://api.africastalking.com/version1/messaging'
            : 'https://api.sandbox.africastalking.com/version1/messaging';
    }

    /**
     * Check if this configuration is for production.
     *
     * @return bool
     */
    public function isProduction(): bool
    {
        return $this->environment === 'production';
    }

    /**
     * Check if this configuration is for sandbox.
     *
     * @return bool
     */
    public function isSandbox(): bool
    {
        return $this->environment === 'sandbox';
    }

    /**
     * Get the masked API key for display purposes.
     * Shows only the first 8 and last 4 characters.
     *
     * @return string
     */
    public function getMaskedApiKey(): string
    {
        $key = $this->api_key;
        $length = strlen($key);
        
        if ($length <= 12) {
            return str_repeat('*', $length);
        }
        
        return substr($key, 0, 8) . str_repeat('*', $length - 12) . substr($key, -4);
    }

    /**
     * Get statistics for this configuration.
     *
     * @return array
     */
    public function getStatistics(): array
    {
        return [
            'total_sent' => $this->logs()->where('status', 'sent')->count(),
            'total_failed' => $this->logs()->where('status', 'failed')->count(),
            'total_pending' => $this->logs()->where('status', 'pending')->count(),
            'total_delivered' => $this->logs()->where('status', 'delivered')->count(),
            'total_cost' => $this->logs()->sum('cost'),
        ];
    }
}
