<?php

namespace Backpack\Pro;

use Backpack\Basset\Facades\Basset;
use Backpack\CRUD\ViewNamespaces;

/**
 * This trait automatically loads package stuff, if they're present
 * in the expected directory. Stick to the conventions and
 * your package will "just work". Feel free to override
 * any of the methods below in your ServiceProvider
 * if you need to change the paths.
 */
trait AutomaticServiceProvider
{
    /**
     * The src directory of the add-on.
     *
     * @var string
     */
    protected string $path;
    
    public function __construct($app)
    {
        $this->app = $app;
        $this->path = realpath(__DIR__.'/..');
    }

    /**
     * -------------------------
     * SERVICE PROVIDER DEFAULTS
     * -------------------------
     */

    /**
     * Boot method may be overrided by AddonServiceProvider
     *
     * @return void
     */
    public function boot(): void
    {
        $this->autoboot();
    }

    /**
     * Perform post-registration booting of services.
     *
     * @return void
     */
    public function autoboot(): void
    {
        if ($this->packageDirectoryExistsAndIsNotEmpty('bootstrap') &&
            file_exists($helpers = $this->packageHelpersFile())) {
            require $helpers;
        }

        if ($this->packageDirectoryExistsAndIsNotEmpty('resources/lang')) {
            $this->loadTranslationsFrom($this->packageLangsPath(), $this->vendorNameSlashPackageName());
        }

        if ($this->packageDirectoryExistsAndIsNotEmpty('resources/views')) {
            // Load published views
            if (is_dir($this->publishedViewsPath())) {
                $this->loadViewsFrom($this->publishedViewsPath(), $this->vendorNameDotPackageName());
            }

            // Fallback to package views
            $this->loadViewsFrom($this->packageViewsPath(), $this->vendorNameDotPackageName());

            // Add default ViewNamespaces
            foreach (['buttons', 'columns', 'fields', 'filters', 'widgets'] as $viewNamespace) {
                if ($this->packageDirectoryExistsAndIsNotEmpty("resources/views/$viewNamespace")) {
                    ViewNamespaces::addFor($viewNamespace, $this->vendorNameDotPackageName()."::{$viewNamespace}");
                }
            }

            // Add basset view path
            Basset::addViewPath($this->packageViewsPath());
        }

        if ($this->packageDirectoryExistsAndIsNotEmpty('database/migrations')) {
            $this->loadMigrationsFrom($this->packageMigrationsPath());
        }

        if ($this->packageDirectoryExistsAndIsNotEmpty('routes')) {
            $this->loadRoutesFrom($this->packageRoutesFile());
        }

        // Publishing is only necessary when using the CLI.
        if ($this->app->runningInConsole()) {
            $this->bootForConsole();
        }
    }

    /**
     * Register any package services.
     *
     * @return void
     */
    public function register(): void
    {
        $this->autoRegister();
    }

    public function autoRegister() 
    {
        if ($this->packageDirectoryExistsAndIsNotEmpty('config')) {
            $this->mergeConfigFrom($this->packageConfigFile(), $this->vendorNameDotPackageName());
        }

        // Registering package commands.
        if (! empty($this->commands)) {
            $this->commands($this->commands);
        }
    }

    /**
     * Console-specific booting.
     *
     * @return void
     */
    protected function bootForConsole(): void
    {
        // Publishing the configuration file.
        if ($this->packageDirectoryExistsAndIsNotEmpty('config')) {
            $this->publishes([
                $this->packageConfigFile() => $this->publishedConfigFile(),
            ], 'config');
        }

        // Publishing the views.
        if ($this->packageDirectoryExistsAndIsNotEmpty('resources/views')) {
            $this->publishes([
                $this->packageViewsPath() => $this->publishedViewsPath(),
            ], 'views');
        }

        // Publishing assets.
        if ($this->packageDirectoryExistsAndIsNotEmpty('resources/assets')) {
            $this->publishes([
                $this->packageAssetsPath() => $this->publishedAssetsPath(),
            ], 'assets');
        }

        // Publishing the translation files.
        if ($this->packageDirectoryExistsAndIsNotEmpty('resources/lang')) {
            $this->publishes([
                $this->packageLangsPath() => $this->publishedLangsPath(),
            ], 'lang');
        }
    }

    /**
     * -------------------
     * CONVENIENCE METHODS
     * -------------------
     */
    protected function vendorNameDotPackageName()
    {
        return $this->vendorName.'.'.$this->packageName;
    }

    protected function vendorNameSlashPackageName()
    {
        return $this->vendorName.'/'.$this->packageName;
    }

    // -------------
    // Package paths
    // -------------

    protected function packageViewsPath()
    {
        return $this->path.'/resources/views';
    }

    protected function packageLangsPath()
    {
        return $this->path.'/resources/lang';
    }

    protected function packageAssetsPath()
    {
        return $this->path.'/resources/assets';
    }

    protected function packageMigrationsPath()
    {
        return $this->path.'/database/migrations';
    }

    protected function packageConfigFile()
    {
        return $this->path.'/config/'.$this->packageName.'.php';
    }

    protected function packageRoutesFile()
    {
        return $this->path.'/routes/'.$this->packageName.'.php';
    }

    protected function packageHelpersFile()
    {
        return $this->path.'/bootstrap/helpers.php';
    }

    // ---------------
    // Published paths
    // ---------------

    protected function publishedViewsPath()
    {
        return base_path('resources/views/vendor/'.$this->vendorName.'/'.$this->packageName);
    }

    protected function publishedConfigFile()
    {
        return config_path($this->vendorNameSlashPackageName().'.php');
    }

    protected function publishedAssetsPath()
    {
        return public_path('vendor/'.$this->vendorNameSlashPackageName());
    }

    protected function publishedLangsPath()
    {
        return resource_path('lang/vendor/'.$this->vendorName);
    }

    // -------------
    // Miscellaneous
    // -------------

    protected function packageDirectoryExistsAndIsNotEmpty($name)
    {
        // check if directory exists
        if (! is_dir($this->path.'/'.$name)) {
            return false;
        }

        // check if directory has files
        foreach (scandir($this->path.'/'.$name) as $file) {
            if ($file != '.' && $file != '..' && $file != '.gitkeep') {
                return true;
            }
        }

        return false;
    }
}
