<?php

namespace Ignite\Core\Models\Source;

use Exception;
use Ignite\Core\Contracts\Source;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Support\Str;

class Manager
{
    /**
     * @var array
     */
    protected $sources;

    /**
     * Manager instance.
     *
     * @param array $sources
     */
    public function __construct(array $sources)
    {
        $this->sources = $sources;
    }

    /**
     * Register a source model.
     *
     * @param string $key
     * @param string $class
     *
     * @return self
     */
    public function register($key, $class)
    {
        $this->sources[$key] = $class;

        return $this;
    }

    /**
     * Interpolate the given value to derive the correct source model.
     *
     * @param array|string $value
     * @param Model|null $model
     *
     * @return array|Source
     * @throws Exception
     */
    public function interpolate($value, Model $model = null)
    {
        // When the value is an array, we don't need to interpolate it, just send it back.
        if (is_array($value)) {
            return $value;
        }

        $value = trim($value);

        // When the value is a comma or pipe-delimited string, split it and return it.
        if (preg_match("/[|,\n]/", $value)) {
            $split = preg_split("/[|,\n]/", $value, -1, PREG_SPLIT_NO_EMPTY);

            if (! is_array($split)) {
                return [$split];
            }

            return $split;
        }

        if (preg_match('/({)([a-zA-Z_]+)(:)?([a-z_,]+)?(})/', $value, $matches)) {
            $key = $matches[2];
            $params = explode(',', $matches[4]);
        } else {
            $key = str_replace(['{', '}'], '', $value);
            $params = [];
        }

        return $this->toDropdown($key, $model, $params);
    }

    /**
     * Get the dropdown array for the source model of the given key.
     *
     * @param string $key
     * @param Model|null $model
     * @param array $params
     *
     * @return array
     * @throws Exception
     */
    public function toDropdown($key, ?Model $model = null, array $params = [])
    {
        return $this->make($key, $model)->toDropdown(...$params);
    }

    /**
     * Make a source model instance from the given key.
     *
     * @param string $key
     * @param Model|null $model
     *
     * @return Source
     * @throws Exception
     */
    public function make($key, ?Model $model = null)
    {
        if (! isset($this->sources[$key])) {
            throw new Exception(
                "Unknown data source `{$key}`. Please check the core.php config file for a matching source model."
            );
        }

        return app($this->sources[$key], compact('model'));
    }
}
