<?php

namespace Clevercherry\Backslash4;

use Illuminate\Support\ServiceProvider as BaseServiceProvider;
use Illuminate\Foundation\Console\AboutCommand;
use Illuminate\Support\Facades\Blade;
use Illuminate\Support\Facades\File;
use Illuminate\Support\Str;
use Illuminate\Support\Carbon;
use Illuminate\Support\Facades\Config;
use Symfony\Component\Finder\Finder;
use Illuminate\Support\Facades\Log;


use Clevercherry\Backslash4\ScoutExtensions\BsTypesenseEngine;
use Laravel\Scout\EngineManager;

class Backslash4ServiceProvider extends BaseServiceProvider
{
    public function register()
    {   //

        if(!file_exists(app_path('Console/Kernel.php')))
        {
            // create the custom kernal in the app
            // because although the file isn't needed in Laravel 11 it is still compatible

            File::ensureDirectoryExists(app_path('Console'));
            File::put(app_path('Console/Kernel.php'),
            "<?php
            namespace App\Console;
            
            use Illuminate\Console\Scheduling\Schedule;
            use Illuminate\Foundation\Console\Kernel as ConsoleKernel;
            
            class Kernel extends ConsoleKernel
            {
            
                /**
                 * Register the commands for the application.
                 *
                 * @return void
                 */
                protected function commands()
                {
                    \$this->load(__DIR__.'/Commands');
            
                    require base_path('routes/console.php');
                }
            }
            ");
        }
    }

    public function boot()
    { 
        
        $this->app->singleton('cleverchery.backslash4.console.kernel', function($app) {
            $dispatcher = $app->make(\Illuminate\Contracts\Events\Dispatcher::class);
            return new \Clevercherry\Backslash4\Console\Kernel($app, $dispatcher);
        });

        $this->app->make('cleverchery.backslash4.console.kernel');

        $about = [];
        if($this->app->runningInConsole())
        {   //only do the about and git stuff if we are running in console
            $dateTimeFormat = config('backslash4.console.datetimeformat','Y-m-d H:i:s (T)');

            $gitBasePath = base_path().'/.git';
            if(file_exists($gitBasePath))
            {   $gitStr = file_get_contents($gitBasePath.'/HEAD');
                $gitBranchName = rtrim(preg_replace("/(.*?\/){2}/", '', $gitStr));
                $gitPathBranch = $gitBasePath.'/refs/heads/'.$gitBranchName;
                //$gitHash = file_get_contents($gitPathBranch);
                $gitDate = date($dateTimeFormat, filemtime($gitPathBranch));
                $about['WebApp git Branch'] = $gitBranchName;
                $about['WebApp git Date']  = $gitDate;
            }
            $about['Path'] = base_path();

            AboutCommand::add('Environment', $about);

            $about = [];

            $gitBasePath = $this->packagePath().'/.git';
            if(file_exists($gitBasePath))
            {   $gitStr = file_get_contents($gitBasePath.'/HEAD');
                $gitBranchName = rtrim(preg_replace("/(.*?\/){2}/", '', $gitStr));
                $about['BS4 git Branch'] = $gitBranchName;
                if($gitBranchName!=='master')
                {
                    $gitPathBranch = $gitBasePath.'/refs/heads/'.$gitBranchName;
                    if(file_exists($gitPathBranch))
                    {   //file does not exist if you're in the middle of a merge
                        $gitDate = date($dateTimeFormat, filemtime($gitPathBranch));
                        $about['BS4 git Date']  = $gitDate;
                        
                        //$gitHash = file_get_contents($gitPathBranch);
                        //$about['BS4 git Hash'] = $gitHash;
                    }
                }
            }
        }

        $about['Version'] = Backslash4::getVersion() . ' ' .Backslash4::getVersionName();
        $about['Copyright'] = '(C) '.Backslash4::integerToRoman(Carbon::now()->year).' CleveryCherry';
        $about['Asset: Config Deployed'] = file_exists(config_path('backslash4.php')) ? 'YES' : 'NO';
        $about['Package Path'] = $this->packagePath();
        AboutCommand::add('Backslash4', $about);

        $this->registerViews();
        $this->registerAnonComponents();

        /**
         * storage configs
         */
        if(file_exists(storage_path('app/config/')))
        {
            //File::ensureDirectoryExists(storage_path('app/config/'));
            foreach (Finder::create()->in(storage_path('app/config'))->name('*.php') as $file)
            {
                $this->mergeConfigFrom( $file->getRealPath() , basename($file->getRealPath(), '.php') );
            }
        }

        /**
         * dependent upon a setting in the app's backslash4 config
         */
        if(config('backslash4.prioritise-bs-routes',0)==0)
        {
            //this version  loads the routes from the package first so that the app routes can overide them
            $this->app->booted(function () {
                # include routing
                include $this->packagePath('routes/web.php');
            });
        } else 
        {   //this version loads the package routes last so the package overrides the app routes
            $this->loadRoutesFrom($this->packagePath('routes/web.php'));
        }

        //$this->loadMigrationsFrom($this->packagePath('database/migrations'));

        $this->registerCommands();

        /* we don't use publishes bs copies/amends files itself as needed
        $this->publishes([
            $this->packagePath('config/backslash4.php') => config_path('backslash4.php')
        ], 'backslash4-config');
        $this->publishes([
            $this->packagePath('resources/views') => resource_path('views/vendor/backslash4'),
        ],'backslash4-views');
        $this->publishes([
            $this->packagePath('public') => public_path('vendor/backslash4'),
        ], 'backslash4-public');
        $this->publishes([
            $this->packagePath('database/migrations/') => database_path('migrations')
        ], 'backslash4-migrations');
        */

        //tenant stuff
        if(!empty(config('backslash4.tenants-on',0)))
        {
            $tenantKey = Backslash4::getTenantKey();
            if(!empty($tenantKey))
            { 
                $tenantInfo = Backslash4::getTenantInfo();

                //test for alternative mail configs
                $this->setTenantMailSettings($tenantInfo);
            
                //add this config file for the tenant
                $config_path=Backslash4::getDashboardConfigPath($tenantInfo);
                if(file_exists($config_path))
                    app('config')->set('tenant', require $config_path);

                $rpath = Backslash4::getTenantPath('route-file', $tenantInfo);
                if(!empty($rpath) && file_exists($rpath) && (filesize($rpath)>10) )
                    $this->loadRoutesFrom($rpath);

                $vpath = Backslash4::getTenantPath('views', $tenantInfo);
                if(!empty($vpath))
                    $this->loadViewsFrom($vpath, 'tenant');
                
               //dd($tenantKey, $config_path, $rpath, $vpath);
            }

            //register all the tenants configs - for use on the command line
            foreach(config('backslash4.tenants',[]) as $tenantKey => $tenantInfo)
            {   
                $config_path=Backslash4::getDashboardConfigPath($tenantInfo);
                if(file_exists($config_path))
                    app('config')->set('tenants.'.$tenantKey, require $config_path);
            }
        }

        //extended ScoutEngines
        if (class_exists(\Typesense\Client::class)) {
            resolve(EngineManager::class)->extend('bs4-typesense', function () {
                return new BsTypesenseEngine();
            });
        }
    }

    /**
     * see if the BS4 config file has settings for the tenant email
     */
    public function setTenantMailSettings($tenantInfo)
	{
        // ie. config('backslash4.tenants.TENANT-KEY.mail')
		$tenantMail = @$tenantInfo['mail'];
        // NOT .settings. config('backslash4.tenants.TENANT-KEY.settings.mail')
        // and NOT the tenants config file
        // settings are very much for the web-app, this is within BS4

		if(!empty($tenantMail)) {

			$config = config('mail', []);

			// for each setting that exists in the tenant file
			// replace the one set in the deafult mail config
			foreach($tenantMail as $key => $value) {
				$config[$key] = $value;
			}
			Log::info('ccdev 177 BS4Service setTenantMailSettings', [$config]);

			Config::set('mail', $config);

			// suggested this is needed - https://stackoverflow.com/questions/23438342/how-to-change-mail-configuration-before-sending-a-mail-in-the-controller-using-l
			(new \Illuminate\Mail\MailServiceProvider(app()))->register();
		}
	}

    private function registerViews()
    {
        $this->loadViewsFrom($this->packagePath('resources/views'), 'backslash4');
        $components=['components', 'layouts'];
        foreach($components as $komp)
        {
            $path = $this->packagePath('resources/views/'.$komp);
            $this->loadViewsFrom($path, 'backslash4');

            $dirs = File::directories($path);
            foreach($dirs as $subdir)
            {
                $this->loadViewsFrom($subdir, 'backslash4::'.$komp);
            }
        }

        //tenant stuff
        if(!empty(config('backslash4.tenants-on',0)))
        {
            $tenantViews = Backslash4::getTenantPath('views');
            if(!empty($tenantViews))
            { 
                $this->loadViewsFrom($tenantViews, Backslash4::getTenantNameSpace() );
            }
        }
    }

    private function registerAnonComponents()
    {
        //register the anonymous compoents and layouts
        $components=['components', 'layouts'];
        foreach($components as $komp)
        {   
            Blade::componentNamespace('backslash4//views//components', 'backslash4');
            Blade::anonymousComponentNamespace('backslash4//resources//views//'.$komp, 'backslash4');
            //^^^^^ above do not work so parse the directory and register components individually

            $path = $this->packagePath('resources/views/'.$komp);
    
            // parse directory tree for anon components
            $files = File::files($this->packagePath('resources/views/'.$komp));
            foreach($files as $file)
            {
                if(Str::endsWith($file,'.blade.php'))
                {
                    $name = basename($file, ".blade.php");
                    Blade::component('backslash4::'.$name, $name);
                }
            }
    
            $debug=[];
            $dirs = File::directories($path);
            foreach($dirs as $subdir)
            {
                $dirname = basename($subdir);
                //$this->loadViewsFrom($subdir, 'backslash4/components');
                //Blade::anonymousComponentNamespace('backslash4/resources/views/'.$komp.'/'.$dirname, 'backslash4');
                //above does not work -- so parse directory tree for anon components

                if(!Str::startsWith($dirname,['.','!']))
                {
                    $files = File::files($subdir);
                    foreach($files as $file)
                    {
                        if(Str::endsWith($file,'.blade.php'))
                        {
                            $name = $dirname.'.'.basename($file, ".blade.php");
                            $debug[]= $name;
                            Blade::component("backslash4::{$name}", $name);
                        }
                    }
                }
            }
            //die(json_encode($debug));
        }

        //tenant stuff
        if(!empty(config('backslash4.tenants-on',0)))
        {
            $tenantKey = Backslash4::getTenantKey();
            
            if(!empty($tenantKey))
            { 
                $tenantViews = Backslash4::getTenantPath('views');
                if(!empty($tenantViews))
                {
                    $tenantNamespace = Backslash4::getTenantNameSpace();

                    $tenantViews = Backslash4::getTenantPath('views');
                    $components=['components', 'layouts'];
                    foreach($components as $komp)
                    {   
                        //dd( Backslash4::getTenantPath('views') );
                        Blade::componentNamespace($tenantViews.'/'.$komp, $tenantNamespace);
                        Blade::anonymousComponentNamespace($tenantViews.'/'.$komp, $tenantNamespace);
                        //^^^^^ above do not work so parse the directory and register components individually

                        $this->loadViewsFrom($tenantViews.'/'.$komp, $tenantNamespace);
        
                        // parse directory tree for anon components
                        File::ensureDirectoryExists($tenantViews);
                        File::ensureDirectoryExists($tenantViews.'/'.$komp);

                        $files = File::files($tenantViews.'/'.$komp);
                        foreach($files as $file)
                        {
                            if(Str::endsWith($file,'.blade.php'))
                            {
                                $name = basename($file, ".blade.php");
                                Blade::component($tenantNamespace.'::'.$name, $name);
                            }
                        }
        
                        $debug=[];
                        $dirs = File::directories($tenantViews.'/'.$komp);
                        foreach($dirs as $subdir)
                        {
                            $dirname = basename($subdir);
                            $this->loadViewsFrom($subdir, $tenantNamespace.'/components');
                            //Blade::anonymousComponentNamespace('backslash4/resources/views/'.$komp.'/'.$dirname, 'backslash4');
                            //above does not work -- so parse directory tree for anon components

                            if(!Str::startsWith($dirname,['.','!']))
                            {
                                $files = File::files($subdir);
                                foreach($files as $file)
                                {
                                    if(Str::endsWith($file,'.blade.php'))
                                    {
                                        $basename = basename($file, ".blade.php");
                                        
                                        if($basename=='index') {
                                            $name = $dirname;
                                        } else {
                                            $name = $dirname.'.'.$basename;
                                        }

                                        $fullname = $dirname.'.'.$basename;
                                        
                                        $debug[]= $name;
                                        Blade::component($tenantNamespace."::{$fullname}", $name);
                                    }
                                }
                            }
                        }
                        //die(json_encode($debug));
                    }
                }

            }
        }
    }

    private function registerCommands()
    {
        //if ($this->app->runningInConsole()) {
        $this->commands([
            Console\Backslash4Command::class,   // main command
            Console\Backslash4Install::class,   //sub-menu
            Console\Backslash4Uninstall::class  //sub-menu
        ]);
    }

    /**
     * return the path of the package
     */
    public static function packagePath($path='')
    {
        return dirname(__DIR__,1)
             . ( empty($path) ? '' : '/' . trim($path, " \n\r\t\v\0\\/"));
    }
}
