<?php

namespace InfyOm\GeneratorBuilder\Controllers;

use InfyOm\Generator\Common\GeneratorConfig;
use App\Http\Controllers\Controller;
use App\Models\Modual;
use Artisan;
use File;
use Illuminate\Support\Str;

use Illuminate\Http\UploadedFile;
use Illuminate\Support\Collection;
use InfyOm\GeneratorBuilder\Requests\BuilderGenerateRequest;
use Request;
use Response;
use Spatie\Permission\Models\Permission;
use Spatie\Permission\Models\Role;

class GeneratorBuilderController extends Controller
{


    public function builder()
    {
        return view(config('infyom.generator_builder.views.builder'));
    }

    public function fieldTemplate()
    {
        return view(config('infyom.generator_builder.views.field-template'));
    }

    public function relationFieldTemplate()
    {
        return view(config('infyom.generator_builder.views.relation-field-template'));
    }

    public function generate(BuilderGenerateRequest $request)
    {
        $data = $request->all();
        $data['modelName'] = str_replace(' ', '-', $data['modelName']); // Replaces all spaces with hyphens.
        $data['modelName'] = preg_replace('/[^A-Za-z]/', '', $data['modelName']); // Removes special chars.
        $str = $data['modelName'];
        if(empty($data['modelName'])){
            return Response::json(['message' => 'This Model name is invalid '], 400);
        }
        if(in_array(strtolower($str),config('infyom.generator_builder.default_moduals')))
        {
            return Response::json(['message' => 'This module is default modual'], 400);
        }
        $isExist = Modual::where('name','LIKE',$str)->first();
        if($isExist){
            return Response::json(['message' => 'This module is already exist, Please rollback module & then try again.'], 400);
        }

        // Validate fields
        if (isset($data['fields'])) {
            $data['fields'][] = [
                'name'=>'id',
                'dbType'=>'increments',
                'htmlType'=>'number',
                'validations'=>'',
                'foreignTable'=>'',
                'isForeign'=>'',
                'searchable'=>'',
                'fillable'=>'',
                'primary'=>'1',
                'inForm'=>'',
                'inIndex'=>'',
            ];
            $data['fields'][] = [
                'name'=>'created_at',
                'dbType'=>'timestamp',
                'htmlType'=>'date',
                'validations'=>'',
                'foreignTable'=>'',
                'isForeign'=>'',
                'searchable'=>'',
                'fillable'=>'',
                'primary'=>'',
                'inForm'=>'',
                'inIndex'=>'',
            ];
            $data['fields'][] = [
                'name'=>'updated_at',
                'dbType'=>'timestamp',
                'htmlType'=>'date',
                'validations'=>'',
                'foreignTable'=>'',
                'isForeign'=>'',
                'searchable'=>'',
                'fillable'=>'',
                'primary'=>'',
                'inForm'=>'',
                'inIndex'=>'',
            ];
            $this->validateFields($data['fields']);

            // prepare foreign key
            $isAnyForeignKey =  collect($data['fields'])->filter(function ($field) {
                return $field['isForeign'] == true;
            });
            if (count($isAnyForeignKey)) {
                $data['fields'] = $this->prepareForeignKeyData($data['fields']);
            }
        }

        // prepare relationship
        if (isset($data['fields']) && !empty($data['relations'])) {
            $data = $this->prepareRelationshipData($data);
        }


        $modual = new Modual();
        $modual->name = $str;
        $modual->save();
        $permissions = [
            'manage-' . $str, 'create-' . $str, 'edit-' . $str, 'delete-' . $str, 'show-' . $str,
        ];
        $role=Role::find(1);

        foreach ($permissions as $permission) {

            $tmp = Permission::create([
                'name' => $permission,
            ]);
            $role->givePermissionTo($tmp);
        }
        $role::bootRefreshesPermissionCache();

        $res = Artisan::call($data['commandType'], [
            'model'         => $data['modelName'],
            '--jsonFromGUI' => json_encode($data),
        ]);

        return Response::json("Files created successfully");
    }

    public function rollback()
    {

        $data = Request::all();
        $data['modelName'] = str_replace(' ', '-', $data['modelName']); // Replaces all spaces with hyphens.
        $data['modelName'] = preg_replace('/[^A-Za-z]/', '', $data['modelName']); // Removes special chars.
        $str = $data['modelName'];
        if(empty($data['modelName'])){
            return Response::json(['message' => 'This Model name is invalid '], 400);
        }
        if(in_array(strtolower($str),config('infyom.generator_builder.default_moduals')))
        {
            return Response::json(['message' => 'This modual is default modual'], 400);
        }

        $input = [
            'model' => $data['modelName'],
            'type'  => $data['commandType'],
        ];

        if (!empty($data['prefix'])) {
            $input['--prefix'] = $data['prefix'];
        }

        Artisan::call('infyom:rollback', $input);

        $permissions = [
            'manage-'.$str,'create-'.$str,'edit-'.$str,'delete-'.$str,'show-'.$str,
        ];
        foreach($permissions as $permission){
            Permission::where('name', $permission)->delete();
        }
        Modual::where('name', $str)->delete();
        Artisan::call('optimize:clear');

        return Response::json(['message' => 'Files rollback successfully'], 200);
    }

    public function generateFromFile()
    {
        $data = Request::all();
        $str = Str::lower($data['modelName']);
        if(in_array($str,config('infyom.generator_builder.default_moduals')))
        {
            return Response::json(['message' => 'This modual is default modual'], 400);

        }

        /** @var UploadedFile $file */
        $file = $data['schemaFile'];
        $filePath = $file->getRealPath();
        $extension = $file->getClientOriginalExtension(); // getting file extension
        if ($extension != 'json') {
            throw new \Exception('Schema file must be Json');
        }

        Artisan::call($data['commandType'], [
            'model'        => $data['modelName'],
            '--fieldsFile' => $filePath,
        ]);

        return Response::json(['message' => 'Files created successfully'], 200);
    }

    private function validateFields($fields)
    {
        $fieldsGroupBy = collect($fields)->groupBy(function ($item) {
            return strtolower($item['name']);
        });

        $duplicateFields = $fieldsGroupBy->filter(function (Collection $groups) {
            return $groups->count() > 1;
        });
        if (count($duplicateFields)) {
            throw new \Exception('Duplicate fields are not allowed');
        }

        return true;
    }

    private function prepareRelationshipData($inputData)
    {
        foreach ($inputData['relations'] as $inputRelation) {
            $relationType = $inputRelation['relationType'];
            $relation = $relationType;
            if (isset($inputRelation['foreignModel'])) {
                $relation .= ',' . $inputRelation['foreignModel'];
            }
            if ($relationType == 'mtm') {
                if (isset($inputRelation['foreignTable'])) {
                    $relation .= ',' . $inputRelation['foreignTable'];
                } else {
                    $relation .= ',';
                }
            }
            if (isset($inputRelation['foreignKey'])) {
                $relation .= ',' . $inputRelation['foreignKey'];
            }
            if (isset($inputRelation['localKey'])) {
                $relation .= ',' . $inputRelation['localKey'];
            }

            $inputData['fields'][] = [
                'type'     => 'relation',
                'relation' => $relation,
            ];
        }
        unset($inputData['relations']);

        return $inputData;
    }

    private function prepareForeignKeyData($fields)
    {
        $updatedFields = [];
        foreach ($fields as $field) {
            if ($field['isForeign'] == true) {
                if (empty($field['foreignTable'])) {
                    throw new \Exception('Foreign table required');
                }
                $inputs = explode(',', $field['foreignTable']);
                $foreignTableName = array_shift($inputs);
                // prepare dbType
                $dbType = $field['dbType'];
                $dbType .= ':unsigned:foreign';
                $dbType .= ',' . $foreignTableName;
                if (!empty($inputs)) {
                    $dbType .= ',' . $inputs['0'];
                } else {
                    $dbType .= ',id';
                }
                $field['dbType'] = $dbType;
            }
            $updatedFields[] = $field;
        }

        return $updatedFields;
    }

    //    public function availableSchema()
    //    {
    //        $schemaFolder = config('infyom.laravel_generator.path.schema_files', base_path('resources/model_schemas/'));
    //
    //        if (!File::exists($schemaFolder)) {
    //            return [];
    //        }
    //
    //        $files = File::allFiles($schemaFolder);
    //
    //        $modelNames = [];
    //
    //        foreach ($files as $file) {
    //            if(File::extension($file) == "json") {
    //                $modelNames[] = File::name($file);
    //            }
    //        }
    //
    //        return Response::json($modelNames);
    //    }
    //
    //    public function retrieveSchema($schema)
    //    {
    //        $schemaFolder = config('infyom.laravel_generator.path.schema_files', base_path('resources/model_schemas/'));
    //
    //        $filePath = $schemaFolder . $schema . ".json";
    //
    //        if (!File::exists($filePath)) {
    //            return Response::json('not found', 402);
    //        }
    //
    //        return Response::json(json_decode(File::get($filePath)));
    //    }
}
