<?php

namespace Ignite\Core\Database\Seeders;

use Illuminate\Database\Seeder;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Support\Str;
use Ignite\Core\Contracts\Database\SeederStrategy;

abstract class AbstractSeeder extends Seeder
{
    /**
     * The path to the data file.
     *
     * @var string
     */
    protected $path = '';

    /**
     * Create a new strategy class.
     *
     * @param  string $name
     * @param  array $params
     * @return SeederStrategy
     */
    public function strategy($name, $params = array())
    {
        $fileKey = 'filepath';
        if (! isset($params[$fileKey]) || empty($params[$fileKey])) {
            throw new \InvalidArgumentException('You must specify a filename.');
        }

        if (-1 === strpos($params[$fileKey], DIRECTORY_SEPARATOR)) {
            $filepath = $this->guessFilenameByConvention($params[$fileKey]);
            if (! is_file($filepath)) {
                throw new \DomainException("The file $filepath does not exist.");
            }
            $params[$fileKey] = $filepath;
        }

        $strategy = $this->createStrategyFromAlias($name, $params);
        if (! $strategy instanceof SeederStrategy) {
            throw new \DomainException("Seeder must implement the SeederStrategy interface.");
        }

        return $strategy;
    }


    /**
     * Run the database seeds.
     */
    public function run()
    {
        Model::unguard();
    }

    /**
     * Create the strategy class from it's alias.
     *
     * @param  string $name
     * @param  array  $params
     * @return SeederStrategy
     */
    protected function createStrategyFromAlias($name, $params)
    {
        $name = Str::studly($name);
        $fqn = "Ignite\\Core\\Database\\Seeders\\Strategy\\$name";

        return app($fqn, $params);
    }

    /**
     * Take a guess at where the data file might exist.
     *
     * @param  string $filename
     * @return string
     */
    protected function guessFilenameByConvention($filename)
    {
        if (! Str::contains('/', $filename)) {
            $filename = base_path(
                sprintf(
                    'modules/%s/database/data/%s',
                    $this->guessModule(),
                    $filename
                )
            );
        }

        return $filename;
    }

    /**
     * Take a guess at which module the data file might exist under.
     *
     * @return string
     */
    protected function guessModule()
    {
        return preg_replace("/(Ignite\\\)([A-Za-z]+)(.*)/", "$2", static::class);
    }

    /**
     * Customize the filepath.
     *
     * @param  string $filename
     * @return bool|string
     */
    protected function getFilepath($filename)
    {
        if (! empty($this->path)) {
            // if path is explicitly set
            return $this->path . $filename;
        } elseif (! empty(config('core.seeder.path'))) {
            // if path is configured and not null
            $path = realpath(base_path(config('core.seeder.path') . '/' . $filename));
            if (false !== $path) {
                return $path;
            }
        }

        // use the Core/database/data path
        return realpath(__DIR__ . '/../../../database/data/' . $filename);
    }
}
