<?php

namespace App\Http\Controllers\User;

use App\Helpers\Security;
use App\Http\Controllers\BaseController;
use App\Models\Organisation;
use App\Models\SecurityEvent;
use App\Models\User;
use App\Notifications\SlackNotification;
use App\Rules\OwnedUserIdentity;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Validator;
use Illuminate\Validation\Rule;
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\Log;
use Illuminate\Support\Facades\Notification;
use Throwable;

class Controller extends BaseController
{
    public function get_user(Request $_r, $_user_id) {
        if($user = User::whereOwned()->where('id', '=', $_user_id)->select('name', 'email', 'group_id')->first()) {
            return response()->json($user, 200);            
        }

        return response()->json(['detail' => 'Error processing the request'], 500);
    }

    public function get_users(Request $_r) {

        return $this->paged_table($_r, function() {
            return User::select('users.id', DB::raw("(CASE WHEN password = '' THEN 0 ELSE 1 END) as is_setup"), DB::raw("(CASE WHEN totp_confirmed_at IS NULL THEN 0 ELSE 1 END) as mfa"), DB::raw('groups.name as group'), 'email', 'phone', DB::raw('users.name as user_name'))
                ->leftJoin('organisations', 'organisation_id', '=', 'organisations.id')
                ->leftJoin('groups', 'group_id', 'groups.id')
                ->where('organisation_id', '=', Auth::user()->organisation_id)
                ->whereNull('organisations.deleted_at');
        }, [ 
            'user_name'         => [ 'db' => 'users.name', 'searchable' => true ],
            'email'             => [ 'db' => 'email', 'searchable' => true ],
            'phone'             => [ 'db' => 'phone', 'searchable' => true ],
            'group'             => [ 'db' => 'groups.name', 'searchable' => false ]
        ], 'users.created_at', null);
    }

    public function create_user(Request $_r) {

        try {

            $valid_request = Validator::make($_r->input(), [
                'name'              => ['required', 'string', 'max:255'],
                'email'             => ['required', 'max:255', 'email:rfc,dns', 'unique:users,email']
            ]);

            $adding_user = Auth::user();                    
            $adding_org = Organisation::find($adding_user->organisation_id);

            if(!$valid_request->fails()) { // Good input

                $user = new User([
                    'name'              => $_r->input('name'),
                    'password'          => '',
                    'email'             => $_r->input('email'),
                    'group_id'          => Auth::user()->group_id,
                    'organisation_id'   => Auth::user()->organisation_id
                ]);

                if($user->save()) {

                    Notification::route('slack', config('creatia.webhook.standard'))->notify(new SlackNotification("Account has been provisioned by $adding_user->name ($adding_org->name) - Name: $user->name, Email: $user->email"));

                    $user->sendSetupEmail();

                    return response()->json(['detail' => 'User created'], 200);
                }

            }
            else { // Bad input
                
                $user_name = $_r->input('name');
                $user_email = $_r->input('email');

                Notification::route('slack', config('creatia.webhook.standard'))->notify(new SlackNotification("Invalid end-user triggered account creation attempt from $adding_user->name ($adding_org->name) - Name: $user_name, Email: $user_email"));

                return response()->json(['detail' => 'Invalid Payload'], 400);

            }

        }
        catch(Throwable $ex) {
            Notification::route('slack', config('creatia.webhook.standard'))->notify(
                new SlackNotification("Error encountered in end-user triggered account creation process.\n\nInput: " . json_encode($_r->input()) . "\n\nError: " . json_encode($ex->getMessage()) . "\n\nLogged in user #" . Auth::user()->id)
            );
            
            Log::debug($ex);
        }

        return response()->json(['detail' => 'Server Error'], 500);
    }

    public function update_user(Request $_r, $_user_id) {

        try {

            $valid_request = Validator::make([ ...$_r->input(), 'user_id' => $_user_id ], [
                'user_id'           => ['required', new OwnedUserIdentity],
                'name'              => ['required', 'string', 'max:255'],
                'email'             => ['required', 'max:255', 'email:rfc,dns', Rule::notIn( User::where('id', '!=', $_user_id)->pluck('email')->toArray() )]
            ]);

            $editing_user = Auth::user();                    
            $editing_org = Organisation::find($editing_user->organisation_id);

            if(!$valid_request->fails()) { // Good input

                $user = User::whereOwned()->where('id', '=', $_user_id)->first() ?? false;

                if($user) {
                    $user->name = $_r->input('name');
                    $user->email = $_r->input('email');

                    if($user->save()) {

                        Notification::route('slack', config('creatia.webhook.standard'))->notify(new SlackNotification("Account has been updated by $editing_user->name ($editing_org->name) - Name: $user->name, Email: $user->email"));

                        return response()->json(['detail' => 'User updated'], 200);
                    }
                }

            }
            else { // Bad input
                
                $user_name = $_r->input('name');
                $user_email = $_r->input('email');

                Notification::route('slack', config('creatia.webhook.standard'))->notify(new SlackNotification("Invalid end-user triggered account modification attempt from $editing_user->name ($editing_org->name) - Name: $user_name, Email: $user_email"));

                return response()->json(['detail' => 'Invalid Payload'], 400);

            }

        }
        catch(Throwable $ex) {
            Notification::route('slack', config('creatia.webhook.standard'))->notify(
                new SlackNotification("Error encountered in end-user triggered account modification process.\n\nInput: " . json_encode($_r->input()) . "\n\nError: " . json_encode($ex->getMessage()) . "\n\nLogged in user #" . Auth::user()->id)
            );
            
            Log::debug($ex);
        }

        return response()->json(['detail' => 'Server Error'], 500);
    }

    public function delete_user(Request $_r, $_user_id) {
        try {
            $valid_request = !Validator::make([ 'id' => $_user_id ], [
                'id' => [ 'required', new OwnedUserIdentity ],
            ])->fails();

            if($valid_request) {

                try {
                    Db::beginTransaction();

                    $user = User::find($_user_id);
                    
                    $user->email = $user->email . '-' . now();
                    $user->password = 'Automated Removal';

                    if($user->save() && $user->delete()) {
                        Db::commit();
                    }
                    else {
                        Db::rollBack();
                    }
                    
                }
                catch(\Exception $ex) {
                    Db::rollBack();
                }

                return response()->json(['detail' => 'User deleted'], 200);
            }
        }
        catch(Throwable $ex) {
            Log::debug($ex);
        }

        return response()->json(['detail' => 'Error deleting user'], 500);
    }

    public function reset_user_mfa(Request $_r, $_user_id) {
        try {
            $valid_request = !Validator::make([ 'id' => $_user_id ], [
                'id' => [ 'required', new OwnedUserIdentity ],
            ])->fails();

            if($valid_request) {

                $user = User::whereOwned()->where('id', '=', $_user_id)->first();

                $user->totp_secret = null;
                $user->totp_confirmed_at = null;
                $user->totp_last_slice = null;
                $user->save();

                $resetting_user = Auth::user();
                $resetting_org = Organisation::find($resetting_user->organisation_id);

                SecurityEvent::create([
                    'user_id'       => $resetting_user->id,
                    'ip'            => Security::real_ip(),
                    'user_agent'    => $_r->userAgent(),
                    'route'         => $_r->path(),
                    'payload'       => json_encode([ 'target_user_id' => $user->id ]),
                    'description'   => 'MFA reset for user',
                ]);

                Notification::route('slack', config('creatia.webhook.standard'))->notify(new SlackNotification("MFA has been reset by $resetting_user->name ($resetting_org->name) - Name: $user->name, Email: $user->email"));

                return response()->json(['detail' => 'MFA reset'], 200);
            }

            return response()->json(['detail' => 'Invalid Payload'], 400);
        }
        catch(Throwable $ex) {
            Log::debug($ex);
        }

        return response()->json(['detail' => 'Server Error'], 500);
    }

}


