<?php

namespace App\Http\Controllers\admin;

use App\admin\Module;
use App\admin\RelationModule;

use Composer\Autoload\ClassLoader;
use Composer\Autoload\Filesystem;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\App;
use App\Http\Requests;
use App\Http\Controllers\Controller;
use Illuminate\Support\Facades\Artisan;
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\File;
use Illuminate\Support\Str;
use Validator;
use Composer\Plugin\CommandEvent;
use Composer\Plugin\PluginEvents;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Input\InputOption;
use Symfony\Component\Console\Output\OutputInterface;


class CrudBuilderController extends Controller
{
    public function normalizePath($path)
    {
        $parts = array();
        $path = strtr($path, '\\', '/');
        $prefix = '';
        $absolute = false;
        if (preg_match('{^( [0-9a-z]{2,}+: (?: // (?: [a-z]: )? )? | [a-z]: )}ix', $path, $match)) {
            $prefix = $match[1];
            $path = substr($path, strlen($prefix));
        }
        if (substr($path, 0, 1) === '/') {
            $absolute = true;
            $path = substr($path, 1);
        }
        $up = false;
        foreach (explode('/', $path) as $chunk) {
            if ('..' === $chunk && ($absolute || $up)) {
                array_pop($parts);
                $up = !(empty($parts) || '..' === end($parts));
            } elseif ('.' !== $chunk && '' !== $chunk) {
                $parts[] = $chunk;
                $up = '..' !== $chunk;
            }
        }
        return $prefix.($absolute ? '/' : '').implode('/', $parts);
    }
    public function isAbsolutePath($path)
    {
        return substr($path, 0, 1) === '/' || substr($path, 1, 1) === ':';
    }
    public function getStaticFile()
    {
        $content = file_get_contents(base_path('vendor/autoload.php'));
        if (preg_match('{ComposerAutoloaderInit([^:\s]+)::}', $content, $match)) {
            $suffix = $match[1];
        }
        $targetDir='';
        $vendorPath='vendor';
        $targetDir = base_path($vendorPath.'/composer/'.$targetDir);
        $staticPhpVersion = 50600;
        $file = <<<HEADER
<?php

// autoload_static.php @generated by Composer

namespace Composer\Autoload;

class ComposerStaticInit$suffix
{

HEADER;

        $loader = new ClassLoader();

        $map = require $targetDir . 'autoload_namespaces.php';
        foreach ($map as $namespace => $path) {
            $loader->set($namespace, $path);
        }

        $map = require $targetDir . '/autoload_psr4.php';
        foreach ($map as $namespace => $path) {
            $loader->setPsr4($namespace, $path);
        }

        $classMap = require $targetDir . '/autoload_classmap.php';
        if ($classMap) {
            $loader->addClassMap($classMap);
        }

        $vendorPathCode = ' => ' . '__DIR__' . " . '../'" . " . '/";
        $appBaseDirCode = ' => ' . '__DIR__' . " . '/";
        $absoluteVendorPathCode = ' => ' .'__DIR__ . "../"';
        $absoluteAppBaseDirCode = ' => ' .'__DIR__ . "../"';
        $initializer = '';
        $prefix = "\0Composer\Autoload\ClassLoader\0";
        $prefixLen = strlen($prefix);
        if (file_exists($targetDir . '/autoload_files.php')) {
            $maps = array('files' => require $targetDir . '/autoload_files.php');
        } else {
            $maps = array();
        }

        foreach ((array) $loader as $prop => $value) {
            if ($value && 0 === strpos($prop, $prefix)) {
                $maps[substr($prop, $prefixLen)] = $value;
            }
        }

        foreach ($maps as $prop => $value) {
            if (count($value) > 32767) {


                $staticPhpVersion = 70000;
            }
            $value = var_export($value, true);
            $value = str_replace($absoluteVendorPathCode, $vendorPathCode, $value);
            $value = str_replace($absoluteAppBaseDirCode, $appBaseDirCode, $value);
            $value = ltrim(preg_replace('/^ */m', '    $0$0', $value));

            $file .= sprintf("    public static $%s = %s;\n\n", $prop, $value);
            if ('files' !== $prop) {
                $initializer .= "            \$loader->$prop = ComposerStaticInit$suffix::\$$prop;\n";
            }
        }

        return $file . <<<INITIALIZER
    public static function getInitializer(ClassLoader \$loader)
    {
        return \Closure::bind(function () use (\$loader) {
$initializer
        }, null, ClassLoader::class);
    }
}

INITIALIZER;
    }

    public function __construct()
    {
        $this->composer = app()['composer'];
    }

    /**
     * @param Request $request
     * @return mixed
     */
    public function migrateRollback(Request $request){

        $name=$request['first_module'];
        $page=$request['page'];
        if($page=='delete_module') {
            exit;
            DB::table('migrations')->where('migration','like', "%_".$name."")->update(['batch'=>2500]);
            $migrations=DB::table('migrations')->where('migration','like', "%_".$name."%")->first();
            Artisan::call("migrate:rollback");
            if($migrations&&file_exists(base_path('database/migrations/'.$migrations->migration.'.php'))){
                File::delete(base_path('database/migrations/'.$migrations->migration.'.php'));
            }
            $migrations1=DB::table('migrations')->where('migration','like', "%_".$name.'Relation'."%")->first();
            if($migrations1&&file_exists(base_path('database/migrations/'.$migrations1->migration.'.php'))){
                File::delete(base_path('database/migrations/'.$migrations1->migration.'.php'));
            }
            $module = Module::orderBy('id', 'desc')->paginate(10);
            return response()->json(['success'],200);
        }else if($page=='relation_module'){
            Artisan::call("migrate");
            return response()->json(['success'], 200);
        }
    }

    /**
     * @param Request $request
     * @return mixed
     */
    public function disableModule(Request $request)
    {
        $module_name= $request['name'];
        /*
        * Check relation
        */
        $first=RelationModule::where("first",$module_name)->first();
        if($first&&$first->first>"")
            return response()->json(['error' => 'You have relation with '. $first->second], 401);
        $second=RelationModule::where("second",$module_name)->first();
        if($second&&$second->first>"")
            return response()->json(['error' => 'You have relation with '. $second->first], 401);

        if($request['data']==1){ ####active module
            #####config/app.php
            $str22='###        '.$module_name.'\\'. $module_name.'ServiceProvider::class'.', //'. $module_name.'  module';
            $str1 = file_get_contents(base_path('config/app.php'));
            $str1q=str_replace($str22,'        '.$module_name.'\\'. $module_name.'ServiceProvider::class'.', //'. $module_name.'  module'.'\n',$str1);
            file_put_contents(base_path('config/app.php'),  $str1q);
            #####composer.json
            $str11 = file_get_contents(base_path('composer.json'));
            $str11=str_replace('"psr-4": {','"psr-4": {'."\n".'            '.'"'.$module_name.'\\\\'.'"'.': '.'"'."modules".'/'.$module_name.'/'.'"'.',',$str11);
            file_put_contents(base_path('composer.json'),  $str11);
            Module::where('name',$request['name'])->update(['status'=>1]);

        }else if($request['data']==0){ ####deactive module

            #####config/app.php
            $str22='        '.$module_name.'\\'. $module_name.'ServiceProvider::class'.', //'. $module_name.'  module';
            $str1 = file_get_contents(base_path('config/app.php'));
            $str1q=str_replace($str22,'###'.$str22.'\n',$str1);
            file_put_contents(base_path('config/app.php'),  $str1q);
            #####composer.json
            $str22='            '.'"'.$module_name.'\\\\'.'"'.': '.'"'."modules".'/'.$module_name.'/'.'"'.',';
            $str11 = file_get_contents(base_path('composer.json'));
            $str11=str_replace($str22,'',$str11);
            file_put_contents(base_path('composer.json'),  $str11);
            Module::where('name',$request['name'])->update(['status'=>0]);
        }
        return response()->json(['success'], 200);
    }

    /**
     * @param Request $request
     * @return mixed
     */
    public function generateModule(Request $request)
    {
        $dir = base_path('modules/'.$request['name'].'/Migration/');
        if (is_dir($dir)){
            if ($dh = opendir($dir)){
                while (($file = readdir($dh)) !== false){
                    if($file!='.' && $file!='..')
                        $migrationsFile= $file;
                }
                closedir($dh);
            }
        }
        $str1 = file_get_contents(base_path('modules/'.$request['name'].'/Migration/'. $migrationsFile));
        $str1=str_replace('array("name" =>"'.$request['name'].'",','array("name" =>"'.$request['name'].'",'.'"description" =>"'.$request['description'].'",',$str1);
        file_put_contents(base_path('modules/'.$request['name'].'/Migration/'. $migrationsFile),$str1);
        Artisan::call("vendor:publish");
        Artisan::call("migrate");

        Module::where('name',$request['name'])->update(['description'=>$request['description']]);
        return response()->json(['success'], 200);
    }

    /**
     * @return mixed
     */
    public function view()
    {
        Artisan::call("vendor:publish");
        Artisan::call("migrate");
        if(Auth::user()->can('view_module')) {
            $module_menus=app('App\Http\Controllers\admin\CrudBuilderController')->createMenumodule();
            $module = Module::orderBy('id','desc')->paginate(10);
            return view('admin.crud_bilder')->with(['module_menus'=>$module_menus,'modules'=>$module,'tab'=>1]);
        }else{
            return redirect('404');
        }
    }

    /**
     * @return string
     */
    public function index()
    {
        $module = Module::orderBy('id','desc')->paginate(10);
        return $module;
    }

    /**
     * @param Request $request
     * @return mixed
     */
    public function store(Request $request)
    {
        $request["name"]=ucfirst($request["name"]);
        $module_fields=$request['fields'];
        $fp = fopen(base_path('public/module_json/'.$request["name"].'.json'), 'w');
        fwrite($fp, $module_fields);
        fclose($fp);
        $validator = Validator::make($request->all(), [
            'name' => 'required|min:3|unique:modules',
            'description' => 'required|min:5',
        ]);
        if ($validator->fails()) {
            return response()->json(['error' => $validator->errors()], 406);
        }
        Artisan::call("infyom:scaffold", ['model' => $request['name'], '--fieldsFile' => 'public/module_json/'.$request["name"].'.json']);
        unset($request['fields']);

        $dir = base_path('modules/'.$request['name'].'/Migration/');
        if (is_dir($dir)){
            if ($dh = opendir($dir)){
                while (($file = readdir($dh)) !== false ){
                    if($file!='.' && $file!='..')
                        $migrationsFile= $file;
                }
                closedir($dh);
            }
        }
        $str1 = file_get_contents(base_path('modules/'.$request['name'].'/Migration/'. $migrationsFile));
        $str1=str_replace('array("name" =>"'.$request['name'].'",','array("name" =>"'.$request['name'].'",'.'"description" =>"'.$request['description'].'",',$str1);
        $add=base_path('modules/'.$request['name']);
        system ("chmod 777 '$add'");
        $add=base_path('modules/'.$request['name'].'/Migration/'. $migrationsFile);
        system ("chmod 777 '$add'");
        file_put_contents(base_path('vendor/composer/autoload_static.php'),$this->getStaticFile());
        Artisan::call("vendor:publish");
        Artisan::call("migrate");
        return response()->json(['success'=>$request->all()], 200);

    }

    /**
     * @param Request $request
     * @param $id
     * @return array
     */
    public function edit(Request $request, $id)
    {
        if(Auth::user()->can('edit_module')) {
            $editmodule = Module::find($id);
            $str = file_get_contents(base_path('public/module_json/' . $editmodule->name . '.json'));
            $editmodule=['tab'=>2,'id'=>$id,'name'=>$editmodule->name,'description'=>$editmodule->description,'fields'=>$str];
            return $editmodule;
        }
    }

    /**
     * @param Request $request
     * @param $id
     * @return mixed
     */
    public function update(Request $request, $id)
    {
        $temp = Module::find($id);
        $module_name = $temp->name;
        $first = RelationModule::where("first", $module_name)->first();
        if ($first && $first->first > "")
            return response()->json(['error' => 'You have relation with ' . $first->second], 401);
        $second = RelationModule::where("second", $module_name)->first();
        if ($second && $second->first > "")
            return response()->json(['error' => 'You have relation with ' . $second->first], 401);
        $request["name"] = ucfirst($request["name"]);
        $module_fields = ($request['fields']);

        if (Auth::user()->can('edit_module')) {  #####check permission
            $validator = Validator::make($request->all(), [
                'name' => 'required|min:3',
                'description' => 'required|min:5',
            ]);
            if ($validator->fails()) {
                return response()->json(['error' => $validator->errors()], 406);
            }
            $this->destroy($id);
            file_put_contents(base_path('public/module_json/' . $request["name"] . '.json'), $module_fields);
            Artisan::call("infyom:scaffold", ['model' => $request['name'], '--fieldsFile' => 'public/module_json/'.$request["name"].'.json']);
            return response()->json(['success' => $request->all()], 200);
        }
    }

    /**
     * @param Request $request
     * @return array
     */
    public function updateSecondLevel(Request $request)
    {
        return response()->json(['success'=>$request->all()], 200);
    }

    /**
     * @param $id
     * @return mixed
     */
    public function destroy($id)
    {
        if(Auth::user()->can('delete_module')) {  #####check permission
            $user=Module::find($id);
            $module_name=$user->name;
            /*
            * Check relation
            */
            $first=RelationModule::where("first",$module_name)->first();
            if($first&&$first->first>"")
                return response()->json(['error' => 'You have relation with '. $first->second], 401);
            $second=RelationModule::where("second",$module_name)->first();
            if($second&&$second->first>"")
                return response()->json(['error' => 'You have relation with '. $second->first], 401);
            DB::table('migrations')->where('migration','like', "%_".$module_name."")->update(['batch'=>2500]);
            $migrations=DB::table('migrations')->where('migration','like', "%_".$module_name."%")->first();
            $migration_name=$migrations->migration;
            Artisan::call("migrate:rollback");
            if($migrations&&file_exists(base_path('database/migrations/'.$migration_name.'.php'))){
                File::delete(base_path('database/migrations/'.$migration_name.'.php'));
            }
            $migrations1=DB::table('migrations')->where('migration','like', "%_".$module_name.'Relation'."%")->first();
            if($migrations1&&file_exists(base_path('database/migrations/'.$migration_name.'.php'))){
                File::delete(base_path('database/migrations/'.$migration_name.'.php'));
            }
            #####config/app.php
            $str22='        '.$module_name.'\\'. $module_name.'ServiceProvider::class'.', //'. $module_name.'  module';
            $str1 = file_get_contents(base_path('config/app.php'));
            $str1q=str_replace($str22,'###'.$str22.'\n',$str1);
            file_put_contents(base_path('config/app.php'),  $str1q);
            #####composer.json
            $str22='            '.'"'.$module_name.'\\\\'.'"'.': '.'"'."modules".'/'.$module_name.'/'.'"'.',';
            $str11 = file_get_contents(base_path('composer.json'));
            $str11=str_replace($str22,'',$str11);
            file_put_contents(base_path('composer.json'),  $str11);
            $user->delete();
            File::deleteDirectory(base_path('modules/' .$module_name));
            $str1 = file_get_contents(base_path('vendor/composer/autoload_psr4.php'));
            $dumpstr="    '".$module_name.'\\\\'."'".'=> array($baseDir . '."'/modules/".$module_name."'),";
            $str11=str_replace($dumpstr,'',$str1);
            file_put_contents(base_path('vendor/composer/autoload_psr4.php'),  $str11);
            $str1 = file_get_contents(base_path('vendor/composer/autoload_classmap.php'));
            $dumpstr="    '".$module_name."'".' => $baseDir . '."'/database/migrations/$migration_name.php',";
            file_put_contents(base_path('vendor/composer/autoload_classmap.php'),  $str11);
            $str11=str_replace($dumpstr,'',$str1);
            file_put_contents(base_path('vendor/composer/autoload_classmap.php'),  $str11);
            $str11=str_replace($dumpstr,'',$str1);
            file_put_contents(base_path('vendor/composer/autoload_classmap.php'),  $str11);
            return response()->json(['first_module'=>$module_name], 200);
        }else{
            return response()->json(['error' => 'You are not loggined'], 401);
        }
    }

    /**
     * @return array
     */
    public function createMenumodule(){
        $remove_array=array();
        $menu=array();
        $child_menu=array();
        $modules=  Module::select('name','link_name')->where('status',1)->get();
        $RelationModule=  RelationModule::where('merge_folder',DB::raw('first'))->lists('first','second')->toarray();
        foreach($modules as $module){
            if(in_array($module->name,$RelationModule) ) {
                foreach($RelationModule as $key=>$val){
                    $child_menu[]=strtolower(str::plural($key));
                }
                $menu[] = ['name'=>$module->link_name, 'child'=>$child_menu];
                array_push($remove_array,$child_menu)  ;
            }
            else{
                $menu[] = ['name'=>$module->link_name, 'child'=>''];
            }
        }
        foreach($menu  as $key=>$val){
            if(in_array($val['name'],$child_menu))
                unset ($menu[$key]);
        }
        return $menu;
    }
}