<?php

namespace App\Http\Controllers\Organisation;

use App\Http\Controllers\BaseController;
use App\Models\Asns;
use App\Models\Organisation;
use App\Models\Suborganisation;
use App\Models\User;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Log;

class AdminController extends BaseController
{
    public function get_parentless_organisation(Request $_r) {
        // Build our query function
        $query_builder = function() {
            return Organisation::select('id', 'name')->whereNotIn('id', function($q) {
                $q->select('child_id')->from('suborganisations');
            });
        };

        // Build our search function
        $query_search = function($prefix_query, $global, $filters) {

            if($global) {
                $prefix_query = $prefix_query->where(function($query) use ($global) {
                    $query->orWhere('name', 'like', "%$global%");
                });
            }

            if($filters) {
                foreach($filters as $filter) {
                    $col = '';
                    switch($filter['id']) {
                        case 'name': $col = 'name'; break;
                    }

                    if($col != '') {
                        $prefix_query = $prefix_query->where($col, 'LIKE', '%' . $filter['value'] . '%');
                    }
                }
            }

            return $prefix_query;
        };

        // Build our sorting function
        $query_sort = function($prefix_query, $column, $direction) {
            return $prefix_query->orderBy('name', $direction ?? 'asc');
        };

        // Create valid sorting keys
        $sorting_keys = ['updated_at', 'name'];

        // Build our transformation function
        $query_transform = function($data) {
            $data->transform(function($row) {
                return $row;
            });

            return $data;
        };

        return BaseController::pagination_table_request($_r, $query_builder, $query_search, $query_sort, $query_transform, $sorting_keys);
    }

    /**
     * Organisation Specific Controller Methods
     */
    public function get_organisations(Request $_r) {
        // Build our query function
        $query_builder = function() {
            return Organisation::select('id', 'name')->whereNotIn('id', function($q) {
                $q->select('child_id')->from('suborganisations');
            });
        };

        // Build our search function
        $query_search = function($prefix_query, $global, $filters) {

            if($global) {
                $prefix_query = $prefix_query->where(function($query) use ($global) {
                    $query->orWhere('name', 'like', "%$global%");
                });
            }

            if($filters) {
                foreach($filters as $filter) {
                    $col = '';

                    switch($filter['id']) {
                        case 'name': $col = "name"; break;
                    }

                    if($col != '') {
                        $prefix_query = $prefix_query->where($col, 'LIKE', '%' . $filter['value'] . '%');
                    }
                }
            }

            return $prefix_query;
        };

        // Build our sorting function
        $query_sort = function($prefix_query, $column, $direction) {
            switch($column) {
                default:
                    $prefix_query = $prefix_query->orderBy('name', $direction ?? 'asc');
            }

            return $prefix_query;
        };

        // Create valid sorting keys
        $sorting_keys = ['updated_at', 'name'];

        // Build our transformation function
        $query_transform = function($data) {
            $data->transform(function($row) {
                return $row;
            });

            return $data;
        };

        return BaseController::pagination_table_request($_r, $query_builder, $query_search, $query_sort, $query_transform, $sorting_keys);
    }

    public function get_suborganisations(Request $_r, $_organisation_id) {
        // Build our query function
        $query_builder = function() use($_organisation_id) {
            return Suborganisation::leftJoin('organisations', 'organisations.id', '=', 'suborganisations.child_id')->where('suborganisations.parent_id', '=', $_organisation_id);
        };

        // Build our search function
        $query_search = function($prefix_query, $global, $filters) {

            if($global) {
                $prefix_query = $prefix_query->where(function($query) use ($global) {
                    $query->orWhere('name', 'like', "%$global%");
                });
            }

            if($filters) {
                foreach($filters as $filter) {
                    $col = '';

                    switch($filter['id']) {
                        case 'name': $col = "name"; break;
                    }

                    if($col != '') {
                        $prefix_query = $prefix_query->where($col, 'LIKE', '%' . $filter['value'] . '%');
                    }
                }
            }

            return $prefix_query;
        };

        // Build our sorting function
        $query_sort = function($prefix_query, $column, $direction) {
            switch($column) {
                default:
                    $prefix_query = $prefix_query->orderBy('name', $direction ?? 'asc');
            }

            return $prefix_query;
        };

        // Create valid sorting keys
        $sorting_keys = ['updated_at', 'name'];

        // Build our transformation function
        $query_transform = function($data) {
            $data->transform(function($row) {
                return $row;
            });

            return $data;
        };

        return BaseController::pagination_table_request($_r, $query_builder, $query_search, $query_sort, $query_transform, $sorting_keys);
    }

    public function get_users(Request $_r, $_organisation_id) {
        // Build our query function
        $query_builder = function() use($_organisation_id) {
            return User::select(DB::raw('users.id, users.name as name, email, phone, groups.name as group'))->leftJoin('groups', 'groups.id', '=', 'users.organisation_id')->where('organisation_id', '=', $_organisation_id);
        };

        // Build our search function
        $query_search = function($prefix_query, $global, $filters) {

            if($global) {
                $prefix_query = $prefix_query->where(function($query) use ($global){
                    $query->orWhere('name', 'like', "%$global%")
                        ->orWhere('email', 'like', "%$global%")
                        ->orWhere('phone', 'like', "%$global%")
                        ->orWhere('group', 'like', "%$global%");
                });
            }

            if($filters) {
                foreach($filters as $filter) {
                    $col = '';
                    switch($filter['id']) {
                        case 'name': $col = 'name'; break;
                        case 'email': $col = 'email'; break;
                        case 'group': $col = 'group'; break;
                        case 'phone': $col = 'phone'; break;
                    }

                    if($col != '') {
                        $prefix_query = $prefix_query->where($col, 'LIKE', '%' . $filter['value'] . '%');
                    }
                }
            }

            return $prefix_query;
        };

        // Build our sorting function
        $query_sort = function($prefix_query, $column, $direction) {
            switch($column) {
                case 'name':
                    $prefix_query = $prefix_query->orderBy('name', $direction);
                    break;
                case 'email':
                    $prefix_query = $prefix_query->orderBy('email', $direction);
                    break;
                case 'group':
                    $prefix_query = $prefix_query->orderBy('group', $direction);
                    break;
                case 'phone':
                    $prefix_query = $prefix_query->orderBy('phone', $direction);
                    break;
            }

            return $prefix_query;
        };

        // Create valid sorting keys
        $sorting_keys = ['updated_at', 'name', 'email', 'group', 'phone'];

        // Build our transformation function
        $query_transform = function($data) {
            $data->transform(function($row) {
                return $row;
            });

            return $data;
        };

        return BaseController::pagination_table_request($_r, $query_builder, $query_search, $query_sort, $query_transform, $sorting_keys);
    }

    public function get_asns(Request $_r, $_organisation_id) {
        // Build our query function
        $query_builder = function() use($_organisation_id) {
            return Asns::where('organisation_id', '=', $_organisation_id);
        };

        // Build our search function
        $query_search = function($prefix_query, $global, $filters) {

            if($global) {
                $prefix_query = $prefix_query->where(function($query) use ($global){
                    $query->orWhere('asn', 'like', "%$global%");
                });
            }

            if($filters) {
                foreach($filters as $filter) {
                    $col = '';

                    switch($filter['id']) {
                        case 'asn': $col = 'asn'; break;
                    }

                    if($col != '') {
                        $prefix_query = $prefix_query->where($col, 'LIKE', '%' . $filter['value'] . '%');
                    }
                }
            }

            return $prefix_query;
        };

        // Build our sorting function
        $query_sort = function($prefix_query, $column, $direction) {
            switch($column) {
                default:
                    $prefix_query = $prefix_query->orderBy('asn', $direction ?? 'asc');
            }

            return $prefix_query;
        };

        // Create valid sorting keys
        $sorting_keys = ['updated_at', 'asn'];

        // Build our transformation function
        $query_transform = function($data) {
            $data->transform(function($row) {
                return $row;
            });

            return $data;
        };

        return BaseController::pagination_table_request($_r, $query_builder, $query_search, $query_sort, $query_transform, $sorting_keys);
    }

    public function post_organisation(Request $_r) {
        $validation_rules = [
            'organisation_name' => ['required', 'string'],
            'user_name' => ['required', 'string'],
            'user_email' => ['required', 'email:rfc,dns'],
        ];

        $response = response()->json(['detail' => 'Error creating customer'], 500);
        
        try {
            if($_r->validate($validation_rules)) {
                $user_name = $_r->input('user_name');
                $user_email = $_r->input('user_email');

                $outcome = DB::transaction(function () use($user_name, $user_email, $_r) {
                    $organisation_id = Organisation::create([
                        'name' => $_r->input('organisation_name')
                    ])->id;

                    $user = new User([
                        'name'              => $user_name,
                        'password'          => '',
                        'email'             => $user_email,
                        'group_id'          => config('security.group_organisation_manager_id'),
                        'organisation_id'   => $organisation_id
                    ]);
        
                    if($user->save()) {
                        $user->sendSetupEmail();

                        return true;
                    }

                    return false;
                });

                if($outcome) {
                    $response = response()->json(['detail' => __('api.200_GENERIC')], 200);
                }
            }

        } catch(Exception $ex) {}

        return $response;
    }

    public function post_user(Request $_r, $organisation_id) {
        $validation_rules = [
            'user_name' => ['required', 'string'],
            'user_email' => ['required', 'email:rfc,dns'],
        ];

        $response = response()->json(['detail' => 'Error creating user'], 500);
        
        try {
            if($_r->validate($validation_rules)) {
                $token = User::make(
                    $_r->input('user_name'),
                    $_r->input('user_email'),
                    config('security.group_organisation_manager_id'),
                    $organisation_id
                );

                $response = response()->json(['email_token' => $token], 200);
            }

        } catch(Exception $ex) {}

        return $response;
    }

    public function post_new_suborganisation(Request $_r, $organisation_id) {
        $validation_rules = [
            'organisation_name' => ['required', 'string'],
            'user_name' => ['required', 'string'],
            'user_email' => ['required', 'email:rfc,dns'],
        ];

        $response = response()->json(['detail' => 'Error creating new sub-organisation'], 500);
        
        try {
            if($_r->validate($validation_rules) && Organisation::find($organisation_id)) {
                $user_name = $_r->input('user_name');
                $user_email = $_r->input('user_email');
                $organisation_name = $_r->input('organisation_name');

                $outcome = DB::transaction(function () use($organisation_name, $user_name, $user_email, $organisation_id) {
                    $child_organisation_id = Organisation::create([
                        'name' => $organisation_name
                    ])->id;

                    Suborganisation::create([
                        'child_id' => $child_organisation_id,
                        'parent_id' => $organisation_id
                    ]);
    
                    $user = new User([
                        'name'              => $user_name,
                        'password'          => '',
                        'email'             => $user_email,
                        'group_id'          => config('security.group_organisation_manager_id'),
                        'organisation_id'   => $child_organisation_id
                    ]);
        
                    if($user->save()) {
                        $user->sendSetupEmail();

                        return true;
                    }
                });

                if($outcome) {
                    $response = response()->json(['detail' => __('api.200_GENERIC')], 200);
                }
            }

        } catch(Exception $ex) {}

        return $response;
    }

    public function post_existing_suborganisation(Request $_r, $organisation_id) {
        $validation_rules = [
            'child_id' => ['required', 'integer'],
        ];

        $response = response()->json(['detail' => 'Error adding existing sub-organisation'], 500);
        
        try {
            $child_id = $_r->input('child_id');

            $valid_organisations = Organisation::whereIn('id', [$organisation_id, $child_id])->count() === 2;

            if($_r->validate($validation_rules) && $valid_organisations) {
                $token = DB::transaction(function () use($organisation_id, $child_id) {
                    Suborganisation::create([
                        'child_id' => $child_id,
                        'parent_id' => $organisation_id
                    ]);
                });

                $response = response()->json(['email_token' => $token], 200);
            }

        } catch(Exception $ex) {}

        return $response;
    }

    public function post_asn(Request $_r, $organisation_id) {
        $response = response()->json(__('api.500_GENERIC'), 500);

        $validation_rules = [
            'asn' => [
                'required',
                'regex:/(?:ASN|AS)*(\d+)?/i'
            ],
            'routelist' => [
                'url'
            ]
        ];

        try {
            $asn = $_r->input('asn');
            $routelist = $_r->input('routelist');

            if($_r->validate($validation_rules)) {
                $outcome = DB::transaction(function () use($asn, $routelist, $organisation_id) {
                    return Asns::make($asn, null, $routelist, $organisation_id, true);
                });

                if($outcome) {
                    $response = response()->json(__('api.200_GENERIC'), 200);                    
                } else {
                    $response = response()->json(__('api.400_INVALID_PAYLOAD'), 400);
                }
            }
        } catch(Exception $ex) {}

        return $response;
    }    
}
