<?php

namespace App\Modules\Workflow\Actions;

abstract class WorkflowBaseAction
{
    /**
     * User friendly name for this action.
     *
     * @var string
     */
    protected $name;

    /**
     * The main event model.
     *
     * @var Eloquent
     */
    protected $event;

    /**
     * The data that gets passed along when the event
     * fires.
     *
     * @var mixed
     */
    protected $event_data = null;

    /**
     * The action model from the database (workflow_actions).
     *
     * @var Eloquent
     */
    protected $action;

    /**
     * Validation rules.
     *
     * @var array
     */
    protected $rules = [];

    /**
     * Validator object.
     *
     * @var \Validator
     */
    protected $validator;

    /**
     * An array containing all the possible variables that can be replaced.
     *
     * @var array
     */
    protected $variables = [];

    /**
     * Default constructor that takes in the event as
     * an argument.
     */
    public function __construct($action, $event, $data = null)
    {
        $this->action = $action;
        $this->event = $event;
        $this->event_data = $data;

        if (! $this->name) {
            $this->name = class_name($this);
        }
    }

    /**
     * Executes all actions assigned to the event.
     *
     * @return mixed
     */
    abstract public function fire();

    /**
     * Returns the event data.
     *
     * @return array
     */
    public function getData()
    {
        return $this->event_data;
    }

    /**
     * Sets the event data.
     *
     * @param array $data
     */
    public function setData($data)
    {
        $this->event_data = $data;
    }

    /**
     * Returns the WorkflowAction.
     *
     * @return App\Modules\Workflow\WorkflowAction
     */
    public function getAction()
    {
        return $this->action;
    }

    /**
     * Returns the action settings stored in the database. This function also replaces
     * all the variables before returning the array. If you want the raw data then consider
     * using the getOriginalSettings() function.
     *
     * @return array
     */
    public function getSettings()
    {
        $settings = $this->getOriginalSettings() ?: [];

        foreach ($settings as $key => $value) {
            $settings[$key] = $this->replaceVariables($value);
        }

        return $settings;
    }

    /**
     * Returns the original settings without replacing any of the variables.
     *
     * @return array | null
     */
    public function getOriginalSettings()
    {
        return $this->getAction()->settings;
    }

    /**
     * Validates the settings array.
     *
     * @return bool
     */
    public function validate()
    {
        $settings = $this->getOriginalSettings() ?: [];
        $this->validator = \Validator::make($settings, $this->rules);

        return ($this->validator->fails()) ? false : true;
    }

    /**
     * Returns a list of all the possible variables that can be replaced.
     *
     * @return array
     */
    protected function getVariables()
    {
        if ($this->variables) {
            return $this->variables;
        }

        $model = $this->getData();
        $this->variables = [];

        foreach ($model->getAttributes() as $key => $value) {
            $this->variables['{'.$key.'}'] = $value;
            $this->variables['{new.'.$key.'}'] = $value;
            $this->variables['{old.'.$key.'}'] = $model->getOriginal($key, $value);
        }

        // Magic variables
        $this->variables['{client_email}'] = $this->getClientEmail();
        $this->variables['{client_name}'] = $model->client ? $model->client->name : '';

        return $this->variables;
    }

    /**
     * Replaces variable in a given string.
     *
     * @param $value (string)
     *
     * @return string
     */
    protected function replaceVariables($value)
    {
        return (is_string($value)) ? strtr($value, $this->getVariables()) : $value;
    }

    /**
     * Attempts to retrive the client email address. If the customer cannot be found
     * or the model does not support a client then an empty string is returned.
     *
     * @return string
     */
    protected function getClientEmail()
    {
        $data = $this->getData();

        // No data is defined, then we can't get any email address
        if (! $data) {
            return '';
        }

        return ($data->client) ? $data->client->email : '';
    }
}
