<?php
/**
 * app/models/log.php
 *
 * Model for handling all logging.
 *
 * @version 3.0
 * @author  Joey Kimsey <Joey@thetempusproject.com>
 * @link    https://TheTempusProject.com
 * @license https://opensource.org/licenses/MIT [MIT LICENSE]
 */
namespace TheTempusProject\Models;

use TheTempusProject\Bedrock\Functions\Check;
use TheTempusProject\Bedrock\Classes\Config;
use TheTempusProject\Canary\Classes\CustomException;
use TheTempusProject\TheTempusProject as App;
use TheTempusProject\Classes\DatabaseModel;
use TheTempusProject\Canary\Bin\Canary as Debug;

class Log extends DatabaseModel {
    public $tableName = 'logs';
    public $configName = 'logging';
    public $modelVersion = '1.0';
    public $configMatrix = [
        'admin' => [
            'type' => 'radio',
            'pretty' => 'Enable Admin Action Logging.',
            'default' => true,
        ],
        'errors' => [
            'type' => 'radio',
            'pretty' => 'Enable Error Logging',
            'default' => true,
        ],
        'logins' => [
            'type' => 'radio',
            'pretty' => 'Enable Login Logging',
            'default' => true,
        ],
    ];
    public $databaseMatrix = [
        [ 'userID', 'int', '11' ],
        [ 'time', 'int', '10' ],
        [ 'ip', 'varchar', '15' ],
        [ 'source', 'varchar', '64' ],
        [ 'action', 'text', '' ],
    ];

    /**
     * The model constructor.
     */
    public function __construct() {
        parent::__construct();
        self::$log = $this;
    }

    public function enabled( $type = '' ) {
        if ( true === parent::enabled() ) {
            return  Config::getValue( 'logging/' . $type ) === true;
        }
        return false;
    }

    public function filter( $data, $params = [] ) {
        foreach ( $data as $instance ) {
            if ( !is_object( $instance ) ) {
                $instance = $data;
                $end = true;
            }
            $toArray = (array) $instance;
            switch ($instance->source) {
                case 'error':
                    $out[] = (object) array_merge( json_decode( $instance->action, true ), $toArray );
                    break;
                default:
                    $instance->logUser = self::$user->getUsername( $instance->userID );
                    $out[] = $instance;
                    break;
            }
            if ( !empty( $end ) ) {
                $out = $out[0];
                break;
            }
        }
        return $out;
    }

    public function list( $filter = null ) {
        $logData = self::$db->get( $this->tableName, [ 'source', '=', $filter ] );
        if ( !$logData->count() ) {
            return false;
        }
        return $this->filter( $logData->results() );
    }

    /**
     * Function to clear logs of a specific type.
     *
     * @param {string} $data - The log type to be cleared
     * @return boolean
     */
    public function clear( $data ) {
        switch ( $data ) {
            case 'admin':
                Debug::error( 'You cannot delete admin logs' );
                return false;
            case 'login':
                self::$db->delete( $this->tableName, [ 'source', '=', $data ] );
                $this->admin( "Cleared Logs: $data" );
                return true;
            case 'error':
                self::$db->delete( $this->tableName, [ 'source', '=', $data ] );
                $this->admin( "Cleared Logs: $data" );
                return true;
            default:
                return false;
        }
    }

    /**
     * logs an error to the DB.
     *
     * @param {int} [$errorID]  - An associated error ID
     * @param {string} [$class]    - Class where the error occurred
     * @param {string} [$function] - method in which the error occurred
     * @param {string} [$error]    - What was the error
     * @param {string} [$data]     - Any additional info
     */
    public function error( $errorID = 500, $class = null, $function = null, $error = null, $data = null ) {
        if ( !$this->enabled( 'errors' ) ) {
            Debug::info( 'Error logging is disabled in the config.' );
            return false;
        }
        $data = [
            'class' => $class,
            'function' => $function,
            'error' => $error,
            'description' => $data,
        ];
        $output = json_encode( $data );
        $fields = [
            'userID' => $errorID,
            'action' => $output,
            'time' => time(),
            'source' => 'error',
        ];
        if ( !self::$db->insert( $this->tableName, $fields ) ) {
            new CustomException( 'logError', $data );
        }
    }

    /**
     * Logs a login to the DB.
     *
     * @param {int} [$userID] - The User ID being logged in.
     * @param {string} [$action] - Must be 'pass' or 'fail'.
     */
    public function login( $userID, $action = 'fail' ) {
        if ( !$this->enabled( 'logins' ) ) {
            Debug::info( 'Login logging is disabled in the config.' );
            return false;
        }
        $fields = [
            'userID' => $userID,
            'action' => $action,
            'time' => time(),
            'source' => 'login',
            'ip' => $_SERVER['REMOTE_ADDR'],
        ];
        if ( !self::$db->insert( $this->tableName, $fields ) ) {
            new CustomException( 'logLogin' );
        }
    }

    /**
     * Logs an admin action to the DB.
     *
     * @param {string} [$action] - Must be 'pass' or 'fail'.
     */
    public function admin( $action ) {
        if ( !$this->enabled( 'admin' ) ) {
            Debug::info( 'Admin logging is disabled in the config.' );
            return false;
        }
        $fields = [
            'userID' => App::$activeUser->ID,
            'action' => $action,
            'time' => time(),
            'source' => 'admin',
            'ip' => $_SERVER['REMOTE_ADDR'],
        ];
        if ( !self::$db->insert( $this->tableName, $fields ) ) {
            new CustomException( 'logAdmin' );
        }
    }
}
