<?php

namespace Fivable\Buildable\Models;

use Illuminate\Database\Eloquent\Collection;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Support\Facades\Artisan;

class BuildableSetting extends Model
{
    /* Columns that are mass-assignable */
    protected $fillable = ['type_mask', 'name', 'slug', 'value'];
    /* Columns to convert to Carbon */
    protected $dates = ['created_at', 'updated_at'];


    /** CRUD Helpers
     * ----------------*/

    /**
     * Generate an index query for BuildableSettings using options
     * @param int|NULL $type_mask
     * @return Collection
     */
    public static function indexFor(int $type_mask = NULL) : Collection
    {
        return static::where('id', '>', 0)
                    ->when(!is_null($type_mask), function($query) use ($type_mask) {
                        $query->where('type_mask', $type_mask);
                    })->get();
    }

    /**
     * Get an associative array of all settings relevant to a public page view
     * @param int $type_mask
     * @return NULL|array
     */
    public static function snailCaseSettings(int $type_mask = NULL) : array
    {
        $generalSettings = static::indexFor($type_mask);
        $settingsArray = [];

        foreach ($generalSettings as $setting) {
            $words = explode("-", $setting->slug);
            for ($i = 0; $i < count($words); $i++) {
                if ($i != 0) {
                    $words[$i] = ucfirst($words[$i]);
                }
            }
            $snailCaseSlug = implode('', $words);
            $settingsArray[$snailCaseSlug] = $setting->value;
        }

        return $settingsArray;
    }

    /**
     * Update all of a type of setting, returning the newly updated setting objects
     * @param array $settingsInfo
     * @return Collection
     */
    public static function updateAll(array $settingsInfo) : Collection
    {
        $type_mask = $settingsInfo['type_mask'];
        $settings = $settingsInfo['settings'];

        foreach ($settings as $setting) {
            $settingObject = static::where('slug', $setting['slug'])->first();
            $settingObject->update([
                'name' => $setting['name'],
                'slug' => $setting['slug'],
                'value' => (gettype($setting['value']) == 'array') ? json_encode($setting['value']) : $setting['value'],
            ]);
        }

        if ($type_mask == 1) {
            Artisan::call('rewrite:variables');
        }

        return static::where('type_mask', $type_mask)->get();
    }

    /**
     * Get buildable-json BuildableSetting and group the contents by category
     * @return array
     */
    public static function buildableJsonByCategory() : array
    {
        $buildableJson = json_decode(BuildableSetting::where('slug', 'buildable-json')->first()->value);
        $groupedArray = [];

        foreach ($buildableJson as $component) {
            $groupedArray[$component->category][] = $component;
        }

        return $groupedArray;
    }


    /** Status Helpers
     * ----------------*/

    /**
     * Get the lowercase string version of this BuildableSetting's type
     * @return string
     */
    public function getTypeString()
    {
        static::staticGetTypeString($this->type_mask);
    }

    /**
     * Generate a type string from a type mask
     * @param int $type_mask
     * @return string
     */
    public static function staticGetTypeString(int $type_mask)
    {
        switch ($type_mask) {
            case 1:
                return 'customization';
            case 2:
                return 'general';
            case 3:
                return 'superadmin';
        }
    }

    /**
     * Generate type mask from type string
     * @param string $type
     * @return int|null
     */
    public static function getTypeMask(string $type)
    {
        switch ($type) {
            case 'customization':
                return 1;
            case 'general':
                return 2;
            case 'superadmin':
                return 4;
            case NULL:
                return NULL;
        }
    }

    /**
     * Determine whether or not the BuildableSetting is a customization
     * @return bool
     */
    public function isCustomization()
    {
        return !!($this->type_mask & 1);
    }

    /**
     * Determine whether or not the BuildableSetting is a general setting
     * @return bool
     */
    public function isGeneralSetting()
    {
        return !!($this->type_mask & 2);
    }

    /**
     * Determine whether or not the BuildableSetting is a Super Admin setting
     * @return bool
     */
    public function isSuperAdminSetting()
    {
        return !!($this->type_mask & 4);
    }
}
