<?php

namespace App\Listeners\PHPXPress;


#use App\Databases;
#use App\Parameters;
#use App\Constraints;
#use App\Repository;
#use App\Permissions;
#use App\ColumnFormats;
#use App\RepositoryColumns;

use App\Helpers\JobDispatcher;
use App\Listeners\Autoflow\PHPXPress\Constraints;
use App\Listeners\Autoflow\PHPXPress\DB;
use Illuminate\Support\Facades\Input;
use Illuminate\Support\Facades\Validator;
use Illuminate\Validation\Rule;
use function d;
use function dd;

#use App\Helpers\InputValidation;

#use Session;


class RepositoryColumns {

    public function __construct()
    {
        #$this->sysDb = Parameters::getValue(Databases::getSelf(), 'sys_db');
    }

    public function getSchema($database) {

        return \Schema::connection($database);

    }

    public function beforeCreateValidation($event) {

        $model = $event->model;

        $event->rules = array(
            'data.signifier'     => ['required', Rule::unique('repository_columns', 'signifier')->where(function ($query) use ($model) {
                    return $query->where('_repository', $model->_repository->getKey());
                })],
        );

    }

    public function persist($event) {

        $model = $event->model;
        $stack = &$event->stack;

        // Export model to xml file
        $serialized = (new \Carbon\Carbon())->format('Y_m_d_') . substr(time(), -6) . '_' .$model->_repository->signifier . '_create_' . $model->signifier . '.xml';
        file_put_contents(database_path('/migrations/' . $serialized), serialize($stack));

        // Create migration script
        $script = file_get_contents(app_path('/Templates/Autoflow/PHPXPress/MigrateRepositoryColumn.php'));
        $script = str_replace('__XML_FILE__', $serialized, $script);
        $script = str_replace('__CLASS_NAME__', \Str::studly($model->_repository->signifier . ' create ' . $model->signifier), $script);
        $scriptfile = (new \Carbon\Carbon())->format('Y_m_d_') . rand(100000,999999) . '_' .$model->_repository->signifier . '_create_' . $model->signifier . '.php';
        file_put_contents(database_path('/migrations/' . $scriptfile), $script);
    }



    public function beforeInsertTransaction($event) {

        $model = $event->model;
        
        //\Artisan::call('migrate');

    }

    public function afterInsertRollback($event) {

        $model = $event->model;

        $schema = $this->getSchema($model->_repository->getAttributeValue('_database'));

        switch($model->form->identifier) {

            case "column":
            case "single_choice":

                if($schema->hasColumn($model->_repository->signifier, $model->signifier))
                    $schema->table($model->_repository->signifier, function ($table) use ($model) {
                        $table->dropColumn($model->signifier);
                    });

                break;

            case "attachment":

                $constraint = \Runtime::make($model->getAttribute('_constraint'));

                if($schema->hasColumn($constraint->getConfig()->signifier, $model->signifier . '_at_' . $model->_repository->signifier))
                    $schema->table($constraint->getConfig()->signifier, function ($table) use ($model) {
                        $table->dropColumn($model->signifier . '_at_' . $model->_repository->signifier);
                    });
                break;
        }
    }

    public function creating($event) {

        $model = $event->model;
        
        switch($model->form->identifier) {

            case "has_one":
            
                $backlink = new \App\Models\PHPXPress\RepositoryColumns();
                $backlink->form = \App\Models\PHPXPress\Forms::findOrFail('0e33971db2811d26687b1ece6fd72f6e04b90fdd');
                $backlink->signifier = $model->signifier . '_at_' . $model->_repository->signifier;
                $backlink->_repository = $model->getAttribute('_constraint');
                $backlink->label = $model->signifier . '_at_' . $model->_repository->signifier;
                $backlink->tooltip = "";
                $backlink->placeholder = "";
                $backlink->storage = 1;
                $backlink->ID = $backlink->getHashId();
                $backlink->save();
                
                $constraint = new \App\Models\PHPXPress\Constraints();
                $constraint->form = \App\Models\PHPXPress\Forms::findOrFail('edaa5baae23de2522ed4a81cbe4314722b3c43ed');
                $constraint->_column = $model->getKey();
                $constraint->_backlink = $backlink->getKey();
                $constraint->_constraint_type = 0;
                $constraint->_left_key = \App\Models\PHPXPress\RepositoryColumns::where('_repository', $model->getAttribute('_constraint'))->where('signifier', 'ID')->first()->getKey();
                $constraint->save();

                unset($model->_constraint);
                
                break;
        
            case "single_choice":

                $backlink = new \App\Models\PHPXPress\RepositoryColumns();
                $backlink->form = \App\Models\PHPXPress\Forms::findOrFail('0e33971db2811d26687b1ece6fd72f6e04b90fdd');
                $backlink->signifier = $model->signifier . '_at_' . $model->_repository->signifier;
                $backlink->_repository = $model->getAttribute('_constraint');
                $backlink->label = $model->signifier . '_at_' . $model->_repository->signifier;
                $backlink->tooltip = "";
                $backlink->placeholder = "";
                $backlink->storage = 1;
                $backlink->ID = $backlink->getHashId();
                $backlink->save();
                
                #dd(5);
                
                //$backlink->saveQuietly();
                //\App\Models\PHPXPress\Meta::addOwner($backlink);
            
                $constraint = new \App\Models\PHPXPress\Constraints();
                $constraint->form = \App\Models\PHPXPress\Forms::findOrFail('edaa5baae23de2522ed4a81cbe4314722b3c43ed');
                $constraint->_column = $model->getKey();
                $constraint->_backlink = $backlink->getKey();
                $constraint->_constraint_type = 1;
                $constraint->_right_key = \App\Models\PHPXPress\RepositoryColumns::where('_repository', $model->getAttribute('_constraint'))->where('signifier', 'ID')->first()->getKey();
                $constraint->save();

                unset($model->_constraint);

                break;

            case "multiselect":

                $backlink = new \App\Models\PHPXPress\RepositoryColumns();
                $backlink->form = \App\Models\PHPXPress\Forms::findOrFail('0e33971db2811d26687b1ece6fd72f6e04b90fdd');
                $backlink->signifier = $model->signifier . '_at_' . $model->_repository->signifier;
                $backlink->_repository = $model->getAttribute('_constraint');
                $backlink->label = $model->signifier . '_at_' . $model->_repository->signifier;
                $backlink->tooltip = "";
                $backlink->placeholder = "";
                $backlink->storage = 1;
                $backlink->ID = $backlink->getHashId();
                $backlink->save();

                //$backlink->saveQuietly();
                //\App\Models\PHPXPress\Meta::addOwner($backlink);

                $constraint = new \App\Models\PHPXPress\Constraints();
                $constraint->form = \App\Models\PHPXPress\Forms::findOrFail('edaa5baae23de2522ed4a81cbe4314722b3c43ed');
                $constraint->_column = $model->getKey();
                $constraint->_backlink = $backlink->getKey();
                $constraint->_constraint_type = 1;
                $constraint->multiselect = 1;

                $constraint->_right_key = \App\Models\PHPXPress\RepositoryColumns::where('_repository', $model->getAttribute('_constraint'))->where('signifier', 'ID')->first()->getKey();
                $constraint->_left_key = \App\Models\PHPXPress\RepositoryColumns::where('_repository', $model->_repository->getKey())->where('signifier', 'ID')->first()->getKey();
                $constraint->save();



                unset($model->_constraint);

                break;

            case "attachment":

                $constrainted = \Runtime::make($model->getAttribute('_constraint'))->getConfig();

                // Wir wandeln hier um ... Backlink wird Column und Column wird Backlink

                $backlink = new \App\Models\PHPXPress\RepositoryColumns();
                $backlink->form = \App\Models\PHPXPress\Forms::findOrFail('0e33971db2811d26687b1ece6fd72f6e04b90fdd');
                $backlink->signifier = $model->signifier;
                $backlink->_repository = $model->_repository->getKey();
                $backlink->label = $model->label;
                $backlink->tooltip = "";
                $backlink->placeholder = "";
                $backlink->storage = 1;
                $backlink->ID = $backlink->getHashId();
                $backlink->save();

                //$backlink->saveQuietly();
                //\App\Models\PHPXPress\Meta::addOwner($backlink);

                $model->signifier = $model->signifier . '_at_' . $model->_repository->signifier;
                $model->_repository = $constrainted->getKey();
                $model->tooltip = "";
                $model->placeholder = "";
                $model->storage = 1;

               
                $constraint = new \App\Models\PHPXPress\Constraints();
                $constraint->form = \App\Models\PHPXPress\Forms::findOrFail('edaa5baae23de2522ed4a81cbe4314722b3c43ed');
                $constraint->_column = $model->getKey();
                $constraint->_backlink = $backlink->getKey();
                $constraint->multiselect = 0;
                $constraint->_constraint_type = 2;
                $constraint->_left_key = \App\Models\PHPXPress\RepositoryColumns::where('_repository', $constrainted->getKey())->where('signifier', 'ID')->first()->getKey();
                $constraint->save();
                
               
                unset($model->_constraint);

                break;

            case "join":

                $constrainted = \Runtime::make($model->getAttribute('_constraint'))->getConfig();



                // Wir wandeln hier um ... Backlink wird Column und Column wird Backlink

                $backlink = new \App\Models\PHPXPress\RepositoryColumns();
                $backlink->form = \App\Models\PHPXPress\Forms::findOrFail('0e33971db2811d26687b1ece6fd72f6e04b90fdd');
                $backlink->signifier = $model->signifier;
                $backlink->_repository = $model->_repository->getKey();
                $backlink->label = $model->label;
                $backlink->tooltip = "";
                $backlink->placeholder = "";
                $backlink->storage = 1;
                $backlink->ID = $backlink->getHashId();
                $backlink->save();

                //$backlink->saveQuietly();
                //\App\Models\PHPXPress\Meta::addOwner($backlink);

                $model->signifier = $model->signifier . '_at_' . $model->_repository->signifier;
                $model->_repository = $constrainted->getKey();
                $model->tooltip = "";
                $model->placeholder = "";
                $model->storage = 1;

                $constraint = new \App\Models\PHPXPress\Constraints();
                $constraint->form = \App\Models\PHPXPress\Forms::findOrFail('edaa5baae23de2522ed4a81cbe4314722b3c43ed');
                $constraint->_column = $model->getKey();
                $constraint->_backlink = $backlink->getKey();
                $constraint->_constraint_type = 2;
                $constraint->multiselect = 1;
                $constraint->_right_key = \App\Models\PHPXPress\RepositoryColumns::where('_repository', $model->getAttribute('_constraint'))->where('signifier', 'ID')->first()->getKey();
                $constraint->_left_key = \App\Models\PHPXPress\RepositoryColumns::where('_repository', $backlink->_repository->getKey())->where('signifier', 'ID')->first()->getKey();
                $constraint->save();

                unset($model->_constraint);

                break;


        }

    }

    public function created($event) {

        $model = $event->model;

    }
    
    
    public function update($event) {

        $model = $event->model;
        $stack = &$event->stack;

        return;
        
        throw new \Exception('not supported yet');

        if(!config("migration.status")) {

            // Export model to xml file
            $serialized = (new \Carbon\Carbon())->format('Y_m_d_') . substr(time(), -6) . '_' .$model->getConfig()->signifier . '_update_' . $model->signifier . '.xml';
            file_put_contents(database_path('/migrations/' . $serialized), serialize($stack));

            // Create migration script
            $script = file_get_contents(app_path('/Templates/Autoflow/PHPXPress/MigrateRepositoryColumn.php'));
            $script = str_replace('__XML_FILE__', $serialized, $script);
            $script = str_replace('__CLASS_NAME__', \Str::studly($model->getConfig()->signifier . ' update ' . $model->signifier), $script);
            $scriptfile = (new \Carbon\Carbon())->format('Y_m_d_') . rand(100000,999999) . '_' .$model->getConfig()->signifier . '_update_' . $model->signifier . '.php';
            file_put_contents(database_path('/migrations/' . $scriptfile), $script);

            // Clear persist stack to stop save execution

            $stack = [];
            return;
        }

    }


    public function updating($event) {

        $model = $event->model;

        return;
        
        throw new \Exception('not supported yet');

        if(\Runtime::$debug) throw new \Exception('bug 123');
        \Runtime::$debug = 1;


        if($model->isDirty('signifier')):

            $model->getConnection()->commit(); // DDL Transaktion freigeben .. siehe BeforeInsertRollback

            $schema = $this->getSchema($event->model->_repository->_database);

            $old = $event->model->getOriginal('signifier');
            $new = $event->model->signifier;

            $dispatch = new JobDispatcher('rename collumn');
            $dispatch->job = function() use ($schema, $event, $old, $new) {

                $schema->table($event->model->_repository->signifier, function ($table) use ($old, $new) {
                    $table->renameColumn($old, $new);
                });

            };
            $dispatch->commit = function() {
                return;
            };
            $dispatch->rollBack = function() use ($schema, $event, $old, $new) {

                // Rolback Schema
                $schema->table($event->model->_repository->signifier, function ($table) use ($old, $new) {
                    $table->renameColumn($new, $old);
                });

                // BeforeInsertRollback committed Model
                $event->model->signifier = $old;
                $event->model->save();
            };
            $event->model->dispatch->push($dispatch);

            endif;

    }

    public function beforeDeleteTransaction($event) {

        // Backup _repository for later.
        // Wird in postDeleteTransaction() benötigt, da zu diesem Zeitpunkt
        // das Vorliegen des Repository nicht mehr gewährleistet ist (für
        // den Fall daß ein Repository mit all seinen Spalten gelöscht wird)
        $event->model->load('_repository');
    }

    public function delete($event) {

        $stack = &$event->stack;
        $model = $event->model;

        throw new \Exception('not supported yet');

        if(!app()->runningInConsole()) {

            $basepath = (new \Carbon\Carbon())->format('Y_m_d_') . substr(time(), -6) . '_' .$model->getConfig()->signifier . '_drop_' . $model->signifier ;

            // Export model to xml file
            $serialized = $basepath . '.xml';
            file_put_contents(database_path('/migrations/' . $serialized), serialize($stack));

            // Create migration script
            $script = file_get_contents(app_path('/Templates/Autoflow/PHPXPress/MigrateDropRepositoryColumn.php'));
            $script = str_replace('__XML_FILE__', $serialized, $script);
            $script = str_replace('__CLASS_NAME__', \Str::studly($model->getConfig()->signifier . ' drop ' . $model->signifier), $script);
            $scriptfile = $basepath . '.php';
            file_put_contents(database_path('/migrations/' . $scriptfile), $script);

            $stack = [];
        }
    }

    public function deletionStart($event) {

        $stack = &$event->stack;
        $model = $event->model;

        throw new \Exception('not supported yet');

        if(!$model->_meta) throw new \Exception($model->getConfig()->signifier . '-->' .$model->getKey() . ' meta missing');
        if(!$model->_meta->_doctype ) throw new \Exception($model->getConfig()->signifier . '-->' .$model->getKey() . ' no doctype');

        switch($model->_meta->_doctype->identifier) {
            case "column"; break;
            case "backlink":

                // Hier unternehmen wir nichts weil wir annehmen daß die zugehörige single_choice-, attachment-, multiselect-
                // oder join-Spalte im selben Zug gesöscht wird

                //$constraint = \Runtime::make('constraints')->where('_backlink', $model->getKey())->first();
                //if(!$constraint) throw new \Exception('constraint missing for ' . $model->getConfig()->getKey() . ' -->' .$model->getKey());
                //$column = $constraint->_column;
                //new \App\Helpers\DeleteHelper($column, $stack);
                break;
            case "single_choice":

                // Delete backlink
                $constraint = \Runtime::make('constraints')->where('_column', $model->getKey())->first();
                if(!$constraint) throw new \Exception('constraint missing for ' . $model->getConfig()->getKey() . ' -->' .$model->getKey());
                $backlink = $constraint->_backlink;
                new \App\Helpers\DeleteHelper($backlink, $stack);

            case "attachment":

                // Delete backlink
                $constraint = \Runtime::make('constraints')->where('_column', $model->getKey())->first();
                if(!$constraint) throw new \Exception('constraint missing for ' . $model->getConfig()->getKey() . ' -->' .$model->getKey());
                $backlink = $constraint->_backlink;
                new \App\Helpers\DeleteHelper($backlink, $stack);

                // Hier löschen wir das verknüpfte Repository
                new \App\Helpers\DeleteHelper($model->_repository, $stack);


            case "multiselect":

                // Delete backlink
                $constraint = \Runtime::make('constraints')->where('_column', $model->getKey())->first();
                if(!$constraint) throw new \Exception('constraint missing for ' . $model->getConfig()->getKey() . ' -->' .$model->getKey());
                $backlink = $constraint->_backlink;
                new \App\Helpers\DeleteHelper($backlink, $stack);

                // Hier löschen wir alle Joins
                $joins = \Runtime::make('form_elements_pivot')->where('_column', $model->getKey())->where('_backlink', $backlink->getKey())->get();
                foreach($joins AS $join) new \App\Helpers\DeleteHelper($join, $stack);

                // Wir lassen die verknüpfte Tabelle bestehen

            case "join":

                // Delete backlink
                $constraint = \Runtime::make('constraints')->where('_column', $model->getKey())->first();
                if(!$constraint) throw new \Exception('constraint missing for ' . $model->getConfig()->getKey() . ' -->' .$model->getKey());
                $backlink = $constraint->_backlink;
                new \App\Helpers\DeleteHelper($backlink, $stack);

                // Hier löschen wir alle Joins
                $joins = \Runtime::make('form_elements_pivot')->where('_column', $model->getKey())->where('_backlink', $backlink->getKey())->get();
                foreach($joins AS $join) new \App\Helpers\DeleteHelper($join, $stack);

                // Hier löschen wir das verknüpfte Repository
                new \App\Helpers\DeleteHelper($model->_repository, $stack);

                break;
            default:
                #dd($model->_meta->_doctype);
                throw new \Exception($model->_meta->_doctype->identifier . ' not supported');

        }

    }

    public function postDeleteTransaction($event) {

        $model = $event->model;

        throw new \Exception('not supported yet');

        // SQL verbietet das Löschen aller Spalten.
        // Wir behalten die ROWID deshalb immer bei.
        if('ROWID' == $model->signifier) return;

        if(\Schema::hasColumn($event->model->_repository->signifier, $event->model->signifier)) {
            \Schema::table($event->model->_repository->signifier, function ($table) use ($event) {
                $table->dropColumn($event->model->signifier);
            });
        }

    }


}
