<?php

namespace Wizard\MagicForger\Replacer;

use Illuminate\Support\Str;

trait Replacer
{
    /**
     * Prefix and Suffix for controller.
     * Usage is up to the user.
     */
    protected string $controller_prefix = '';

    /**
     * Prefix and Suffix for controller.
     * Usage is up to the user.
     */
    protected string $controller_suffix = 'Controller';

    /**
     * Finds all places in a string that could be replaced.
     * Returns an array of all potential replacements as they appear in the target.
     */
    public function get_all_keywords(string $target): array
    {
        // find all matches to our expected syntax
        $matches = [];
        preg_match_all('/{{[\sa-zA-Z\-_]+}}/', $target, $matches);
        // sort the array and return unique values
        sort($matches[0]);

        return array_values(array_unique($matches[0]));
    }

    /**
     * Apply replacements to the target string.
     */
    public function apply_replacements(string $target): string
    {
        $inserts = $this->get_all_keywords($target);
        $available_replacements = $this->get_available_replacements();

        return str_replace(
            array_keys($available_replacements),
            $available_replacements,
            $target
        );
    }

    /**
     * Get available replacements for string replacements.
     */
    public function get_available_replacements(): array
    {
        $table_name = $this->getTableInput();

        return [
            '{{ class }}' => $this->getClassName($table_name),
            '{{ controllerName }}' => $this->controller_name($table_name),
            '{{ model }}' => $this->model_name($table_name),
            '{{ modelVariable }}' => $this->model_variable($table_name),
            '{{ namespace }}' => $this->{'get'.$this->type.'Namespace'}($table_name),
            '{{ namespacedModel }}' => $this->getNamespacedModel($table_name),
            '{{ requestUses }}' => $this->getRequestUses($table_name),
            '{{ rootNamespace }}' => $this->getRootNamespace(),
            '{{ storeRequest }}' => $this->store_request_name($table_name),
            '{{ filterRequest }}' => $this->filter_request_name($table_name),
            '{{ updateRequest }}' => $this->update_request_name($table_name),
            '{{ tableName }}' => $table_name,
        ];
    }

    // Model and Controller Naming

    /**
     * Generate model name in Studly case.
     */
    public function model_name(string $name): string
    {
        return Str::singular(Str::studly($name));
    }

    /**
     * Generate singular model variable name.
     */
    public function model_variable(string $name): string
    {
        return Str::singular($name);
    }

    /**
     * Generate controller name using prefix/suffix and studly case.
     */
    public function controller_name(string $name): string
    {
        return $this->controller_prefix.
            $this->model_name($name).
            $this->controller_suffix;
    }

    /**
     * Generate the store request name.
     */
    public function store_request_name(string $name): string
    {
        return 'Store'.$this->model_name($name).'Request';
    }

    /**
     * Generate the filter request name.
     */
    public function filter_request_name(string $name): string
    {
        return 'Filter'.$this->model_name($name).'Request';
    }

    /**
     * Generate the update request name.
     */
    public function update_request_name(string $name): string
    {
        return 'Update'.$this->model_name($name).'Request';
    }


    /**
     * Generate the index view name.
     */
    public function index_view_name(string $name): string
    {
        return '';
    }

    /**
     * Generate the create_edit view name.
     */
    public function create_edit_view_name(string $name): string
    {
        return '';
    }

    /**
     * Generate the show view name.
     */
    public function show_view_name(string $name): string
    {
        return '';
    }


    /**
     * Generate route name in Studly case.
     */
    public function routes_name(string $name): string
    {
        return Str::singular(Str::studly($name));
    }

    // Namespace Methods
    // These methods handle the formation of various namespaces used within the replacements.

    /**
     * Get the root namespace for the application.
     */
    public function getRootNamespace(): string
    {
        return $this->laravel->getNamespace();
    }

    /**
     * Get the model namespace.
     */
    public function getRouteNamespace(string $name = ''): string
    {
			return base_path()
				. DIRECTORY_SEPARATOR . 'routes' 
				. DIRECTORY_SEPARATOR . 'resources'
				;
    }

    /**
     * Get the model namespace.
     */
    public function getModelNamespace(string $name = ''): string
    {
        return $this->getRootNamespace().'Models';
    }

    /**
     * Get the fully-qualified namespaced model class.
     */
    public function getNamespacedModel(string $name = ''): string
    {
        return $this->getModelNamespace().'\\'.$this->model_name($name);
    }

    /**
     * Get the controller namespace.
     */
    public function getControllerNamespace(string $name = ''): string
    {
        return $this->getRootNamespace().'Http\\Controllers';
    }

    /**
     * Get the request namespace.
     */
    public function getRequestNamespace(string $name): string
    {
        return $this->getRootNamespace().'Http\\Requests\\'.$this->model_name($name);
    }

    /**
     * Get the store request namespace.
     */
    public function getStoreRequestNamespace(string $name): string
    {
        return $this->getRequestNamespace($name);
    }

    /**
     * Get the filter request namespace.
     */
    public function getFilterRequestNamespace(string $name): string
    {
        return $this->getRequestNamespace($name);
    }

    /**
     * Get the update request namespace.
     */
    public function getUpdateRequestNamespace(string $name): string
    {
        return $this->getRequestNamespace($name);
    }

    /**
     * Get the view namespace.
     */
    public function getViewNamespace(string $name): string
    {
        return $this->viewPath($name) . '\\';
    }

    /**
     * Get the index view namespace.
     */
    public function getIndexViewNamespace(string $name): string
    {
        return $this->getViewNamespace($name) . '\\';
    }

    /**
     * Get the create_edit view namespace.
     */
    public function getCreateEditViewNamespace(string $name): string
    {
        return $this->getViewNamespace($name) . '\\';
    }

    /**
     * Get the show view namespace.
     */
    public function getShowViewNamespace(string $name): string
    {
        return $this->getViewNamespace($name) . '\\';
    }


    /**
     * Get the request uses string for replacement.
     */
    public function getRequestUses(string $name): string
    {
        return implode("\n", [
            'use '.$this->getRequestNamespace($name).'\\'.$this->store_request_name($name).';',
            'use '.$this->getRequestNamespace($name).'\\'.$this->filter_request_name($name).';',
            'use '.$this->getRequestNamespace($name).'\\'.$this->update_request_name($name).';',
        ]);
    }

    // Text Manipulation

    /**
     * Convert a string to a human-readable format.
     * Assumes camel case input.
     */
    public function human_readable(string $name): string
    {
        return Str::title(Str::replace('_', ' ', $name));
    }

    /**
     * Convert a string to a lowercase human-readable format.
     * Assumes camel case input.
     */
    public function human_readable_lc(string $name): string
    {
        return Str::lower($this->human_readable($name));
    }
}
