<?php
/**
 * app/classes/preferences.php
 *
 * This class handles all the hard-coded preferences.
 *
 * @version 3.0
 * @author  Joey Kimsey <Joey@thetempusproject.com>
 * @link    https://TheTempusProject.com
 * @license https://opensource.org/licenses/MIT [MIT LICENSE]
 */
namespace TheTempusProject\Classes;

use TheTempusProject\Houdini\Classes\Issues;
use TheTempusProject\Houdini\Classes\Forms;
use TheTempusProject\Houdini\Classes\Template;
use TheTempusProject\Canary\Bin\Canary as Debug;
use TheTempusProject\Bedrock\Functions\Check;
use TheTempusProject\Bedrock\Functions\Upload;
use TheTempusProject\Bedrock\Functions\Input;
use TheTempusProject\TheTempusProject as App;
use TheTempusProject\Bedrock\Classes\Config;

class Preferences {
    public static $preferences = false;
    private static $location = false;
    private static $initialized = false;

    /**
     * Default constructor which will attempt to load the preferences from the location specified.
     *
     * @param {string} [$location]
     * @return {null|object}
     */
    public function __construct( $location = '' ) {
        if ( self::$initialized !== false ) {
            Debug::log( 'Preferences already initialized.' );
            return $this;
        }
        if ( empty( $location ) ) {
            $location = PREFERENCES_JSON;
        }
        self::$initialized = $this->load( $location );
        if ( self::$initialized !== false ) {
            Debug::log( 'Preferences initialization succeeded.' );
            return $this;
        }
        Debug::warn( 'Preferences initialization failed.' );
    }

    /**
     * Attempts to retrieve then set the preferences from a file.
     * @note This function will reset the preferences every time it is used.
     *
     * @param {string} [$location]
     * @return {bool}
     */
    public function load( $location ) {
        self::$preferences = $this->getPrefsFile( $location );
        self::$location = $location;
        if ( self::$preferences === false || empty( self::$preferences ) ) {
            Debug::warn( 'Preferences load failed.' );
            return false;
        }
        Debug::log( 'Preferences load succeeded.' );
        return true;
    }

    /**
     * Opens and decodes the preferences json from the location provided.
     *
     * @param {string} [$location]
     * @return {bool|array}
     */
    public function getPrefsFile( $location ) {
        if ( file_exists( $location ) ) {
            Debug::debug( "Preferences json found: $location" );
            return json_decode( file_get_contents( $location ), true );
        } else {
            Debug::warn( "Preferences json not found: $location" );
            return false;
        }
    }

    /**
     * Retrieves the preference option for $name.
     *
     * @param {string} [$name]
     * @return {WILD}
     */
    public static function get( $name ) {
        if ( self::$preferences === false ) {
            return Debug::warn( 'Preferences not loaded.' );
        }
        if ( isset( self::$preferences[$name] ) ) {
            return self::$preferences[$name];
        }
        return Debug::warn( "Preference not found: $name" );
    }

    public function getType( $name ) {
        $pref = $this->get( $name );
        if ( empty( $pref ) || empty( $pref['type'] ) ) {
            return Debug::warn( "Preference Type not found: $name" );
        }
        return $pref['type'];
    }

    public function getDefault( $name ) {
        $pref = $this->get( $name );
        if ( empty( $pref ) || empty( $pref['default'] ) ) {
            return Debug::warn( "Preference Default not found: $name" );
        }
        return $pref['default'];
    }

    public function getOptions( $name ) {
        $pref = $this->get( $name );
        if ( empty( $pref ) || empty( $pref['options'] ) ) {
            return Debug::warn( "Preference Options not found: $name" );
        }
        return $pref['options'];
    }

    public function getPrettyName( $name ) {
        $pref = $this->get( $name );
        if ( empty( $pref ) || empty( $pref['pretty'] ) ) {
            return Debug::warn( "Preference Pretty Name not found: $name" );
        }
        return $pref['pretty'];
    }

    /**
     * Saves the current preferences.
     *
     * @param {bool} [$default] - Whether or not to save a default copy.
     * @return {bool}
     */
    public function save( $backup = true ) {
        if ( self::$preferences === false ) {
            Debug::warn( 'Preferences not loaded.' );
            return false;
        }
        if ( self::$location === false ) {
            Debug::warn( 'Preferences location not set.' );
            return false;
        }
        if ( $backup ) {
            $locationArray = explode( '.', self::$location );
            $locationArray[] = 'bak';
            $backupLoction = implode( '.', $locationArray );
            if ( !file_put_contents( $backupLoction, json_encode( self::$preferences ) ) ) {
                return false;
            }
        }
        if ( file_put_contents( self::$location, json_encode( self::$preferences ) ) ) {
            return true;
        }
        return false;
    }

    /**
     * Adds a new preference to the $preferences array.
     *
     * @param {string} [$name]
     * @param {string} [$value]
     * @return {bool}
     */
    public function add( $name, $details ) {
        if ( !Check::simpleName( $name ) ) {
            Debug::error( "Preference name invalid: $name" );
            return false;
        }
        if ( isset( self::$preferences[$name] ) ) {
            Debug::warn( "Preference already exists: $name" );
            return false;
        }
        if ( self::$preferences === false ) {
            self::$preferences = [];
        }
        $prefsArray = $this->normalizePreferenceArray( $name, $details );
        if ( false === $prefsArray ) {
            Debug::warn( 'Preference array failed to load properly.' );
            return false;
        }
        self::$preferences[$name] = $prefsArray;
        return true;
    }

    public function getFormHtml( $populated = [] ) {
        // dv( self::$preferences );
        $form = '';
        // Added so i can force some sort of ordering
        $inputTypes = [
            'file' => [],
            'select' => [],
            'timezone' => [],
            'checkbox' => [],
            'switch' => [],
        ];
        foreach ( self::$preferences as $name => $details ) {
            $tempPrefsArray = $this->normalizePreferenceArray( $name, $details );
            if ( isset( $populated[ $name ] ) ) {
                $tempPrefsArray['value'] = $populated[$name];
            } else {
                $tempPrefsArray['value'] = $tempPrefsArray['default'];
            }
            // $form .= Forms::getFormFieldHtml( $name, $tempPrefsArray['pretty'], $tempPrefsArray['type'], $tempPrefsArray['default'], $tempPrefsArray['options'] );
            if ( $tempPrefsArray['type'] == 'checkbox' ) {
                $tempPrefsArray['type'] = 'switch';
            }

            if ( 'file' === $tempPrefsArray['type'] ) {
                // dv( Config::getValue( 'uploads/images' ) );
                if ( ! Config::getValue( 'uploads/images' ) ) {
                    Debug::info( 'Preference hidden because uploads are disabled.' );
                    continue;
                }
            }

            $inputTypes[ $tempPrefsArray['type'] ][] = self::getFormFieldHtml( $name, $tempPrefsArray['pretty'], $tempPrefsArray['type'], $tempPrefsArray['value'], $tempPrefsArray['options'] );
        }
        foreach ( $inputTypes as $skip => $items ) {
            $form .= implode( ' ', $items );
        }
        return $form;
    }

    public static function getFormFieldHtml( $fieldname, $fieldTitle, $type, $defaultValue = '', $options = null ) {
        $html = '';
        switch ( $type ) {
            case 'radio':
            case 'bool':
            case 'boolean':
                $fieldHtml = Forms::getRadioHtml( $fieldname, [ 'true', 'false' ], $defaultValue );
                break;
            case 'select':
                $fieldHtml = Forms::getSelectHtml( $fieldname, $options, $defaultValue );
                break;
            case 'customSelect':
                if ( empty( $options ) ) {
                    $options = '{' . $fieldname . '-options}';
                }
                $fieldHtml = Forms::getSelectHtml( $fieldname, $options, $defaultValue );
                break;
            case 'block':
                $fieldHtml = Forms::getTextBlockHtml( $fieldname, $defaultValue );
                break;
            case 'text':
            case 'url':
                $fieldHtml = Forms::getTextHtml( $fieldname, $defaultValue );
                break;
            case 'checkbox':
                $fieldHtml = Forms::getCheckboxHtml( $fieldname, $defaultValue );
                break;
            case 'switch':
                $fieldHtml = Forms::getSwitchHtml( $fieldname, $defaultValue );
                break;
            case 'timezone':
                $fieldHtml = Forms::getTimezoneHtml( $defaultValue );
                break;
            case 'file':
                $fieldHtml = Forms::getFileHtml( $fieldname );
                break;
            default:
                Debug::error( "unknown field type: $type" );
                break;
        }

        $html .= '<div class="mb-3 row">';
        $html .= '<label for="' . $fieldname . '" class="col-lg-6 col-form-label text-end">' . $fieldTitle . '</label>';
        $html .= '<div class="col-lg-6">';
        $html .= $fieldHtml;
        $html .= '</div>';
        if ( 'file' === $type ) {
            $html .= '<div class="mb-3 row">';
            $html .= '<h4 class="col-lg-6 col-form-label text-end">Current Image</h4>';
            $html .= '<div class="col-lg-6">';
            $html .= '<img alt="User Avatar" src="{ROOT_URL}' . $defaultValue . '" class="img-circle img-fluid p-2 avatar-125">';
            $html .= '</div>';
        }
        $html .= '</div>';
        return Template::parse( $html );
    }

    public function convertFormToArray( $fillMissing = true, $defaultsOnly = true ) {
        $prefsArray = [];
        foreach ( self::$preferences as $name => $details ) {
            if ( true === $fillMissing ) {
                if ( true !== $defaultsOnly && !empty( App::$activePrefs[$name] ) ) {
                    $prefsArray[$name] = App::$activePrefs[$name];
                } else {
                    $prefsArray[$name] = $details['default'];
                }
            }
            if ( Input::exists( $name ) ) {
                $prefsArray[$name] = Input::post( $name );
            }
            if ( 'file' == $details['type'] ) {
                if ( Input::exists( $name ) ) {
                    $folder = UPLOAD_DIRECTORY . App::$activeUser->username . DIRECTORY_SEPARATOR . 'images' . DIRECTORY_SEPARATOR;
                    $upload = Upload::image( $name, $folder );
                    if ( $upload ) {
                        $route = str_replace( APP_ROOT_DIRECTORY, '', $folder );
                        $prefsArray[$name] = $route . Upload::last();
                    } else {
                        Issues::add( 'error', [ 'There was an error with your upload.' => Check::userErrors() ] );
                        unset( $prefsArray[$name] );
                    }
                }
            }
            if ( 'checkbox' == $details['type'] ) {
                if ( Input::exists( $name ) ) {
                    $prefsArray[$name] = true;
                } else {
                    $prefsArray[$name] = false;
                }
            }
        }
        return $prefsArray;
    }

    public function getDefaultPreferencesArray() {
        if ( self::$preferences === false ) {
            Debug::warn( 'Preferences not loaded.' );
            return false;
        }
        $prefsArray = [];
        foreach ( self::$preferences as $name => $details ) {
            $tempPrefsArray = $this->normalizePreferenceArray( $name, $details );
            $prefsArray[$name] = $tempPrefsArray['default'];
        }
        return $prefsArray;
    }

    public function normalizePreferenceArray( $name, $prefsArray ) {
        if ( !is_array( $prefsArray ) ) {
            Debug::warn( 'Preference array was not an array.' );
            return false;
        }
        if ( !isset( $prefsArray['type'] ) ) {
            if ( isset( $prefsArray['options'] ) ) {
                $prefsArray['type'] = 'select';
            } else {
                $prefsArray['type'] = 'text';
            }
        }
        if ( !isset( $prefsArray['pretty'] ) ) {
            $prefsArray['pretty'] = ucfirst( $name );
        }
        if ( !isset( $prefsArray['default'] ) ) {
            $prefsArray['default'] = '';
        }
        if ( ( empty( $prefsArray['avatar'] ) ) || ( $prefsArray['avatar'] == 'defaultAvatar.png' ) ) {
            $prefsArray['avatar'] = IMAGE_DIRECTORY . 'defaultAvatar.png';
        }
        if ( !isset( $prefsArray['options'] ) ) {
            $prefsArray['options'] = null;
        }
        return $prefsArray;
    }

    /**
     * Removes an existing preference from the $preferences array.
     *
     * @param {string} [$name]
     * @param {bool} [$save]
     * @return {bool}
     */
    public function remove( $name, $save = false ) {
        if ( self::$preferences === false ) {
            Debug::warn( 'Preferences not loaded.' );
            return false;
        }
        if ( !isset( self::$preferences[$name] ) ) {
            Debug::error( "Preference does not exist: $name" );
            return false;
        }
        unset( self::$preferences[$name] );
        if ( $save === true ) {
            return $this->save( true );
        }
        return true;
    }
}
