<?php

namespace App\Models;

use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Support\Facades\Cache;
use Illuminate\Support\Facades\Crypt;

class Setting extends Model
{
    use HasFactory;

    /**
     * The attributes that are mass assignable.
     *
     * @var array
     */
    protected $fillable = [
        'key',
        'value',
        'type',
        'group',
        'description',
    ];

    /**
     * Get a setting value by key.
     *
     * @param  string  $key
     * @param  mixed  $default
     * @return mixed
     */
    public static function get($key, $default = null)
    {
        $cacheKey = "setting_{$key}";
        
        return Cache::rememberForever($cacheKey, function () use ($key, $default) {
            $setting = self::where('key', $key)->first();
            
            if (!$setting) {
                return $default;
            }
            
            return self::castValue($setting->value, $setting->type);
        });
    }

    /**
     * Set a setting value by key.
     *
     * @param  string  $key
     * @param  mixed  $value
     * @return void
     */
    public static function set($key, $value)
    {
        $setting = self::updateOrCreate(
            ['key' => $key],
            ['value' => self::prepareValue($value)]
        );
        
        // Clear cache
        Cache::forget("setting_{$key}");
        
        return $setting;
    }

    /**
     * Cast value based on type.
     *
     * @param  mixed  $value
     * @param  string  $type
     * @return mixed
     */
    private static function castValue($value, $type)
    {
        if ($value === null) {
            return null;
        }
        
        switch ($type) {
            case 'boolean':
                return filter_var($value, FILTER_VALIDATE_BOOLEAN);
            case 'integer':
                return (int) $value;
            case 'json':
                return json_decode($value, true);
            default:
                return $value;
        }
    }

    /**
     * Prepare value for storage.
     *
     * @param  mixed  $value
     * @return string
     */
    private static function prepareValue($value)
    {
        if (is_array($value) || is_object($value)) {
            return json_encode($value);
        }
        
        if (is_bool($value)) {
            return $value ? '1' : '0';
        }
        
        return (string) $value;
    }

    /**
     * Get all settings by group.
     *
     * @param  string  $group
     * @return \Illuminate\Database\Eloquent\Collection
     */
    public static function getByGroup($group)
    {
        return self::where('group', $group)->orderBy('key')->get();
    }

    /**
     * Get encrypted password value.
     *
     * @param  string  $key
     * @return string|null
     */
    public static function getEncrypted($key)
    {
        $value = self::get($key);
        
        if (empty($value)) {
            return null;
        }
        
        try {
            return Crypt::decryptString($value);
        } catch (\Exception $e) {
            return $value; // Return as-is if decryption fails (might be plain text)
        }
    }

    /**
     * Set encrypted password value.
     *
     * @param  string  $key
     * @param  string  $value
     * @return void
     */
    public static function setEncrypted($key, $value)
    {
        if (empty($value)) {
            self::set($key, '');
            return;
        }
        
        $encrypted = Crypt::encryptString($value);
        self::set($key, $encrypted);
    }

    /**
     * Clear all settings cache.
     *
     * @return void
     */
    public static function clearCache()
    {
        $settings = self::pluck('key');
        foreach ($settings as $key) {
            Cache::forget("setting_{$key}");
        }
    }
}

