<?php

namespace App\Http\Controllers\Whmcs;

use Illuminate\Http\Request;
use Illuminate\Foundation\Auth\Access\AuthorizesRequests;
use App\Models\User;
use App\Models\Group;
use App\Models\Organisation;
use App\Http\Controllers\BaseController;
use App\Models\Goliath\GoliathOrganisationAttributes;
use App\Models\Mercury\MercuryOrganisationAttributes;
use App\Models\OrganisationExternalIdentities;
use App\Models\Suborganisation;
use App\Notifications\SlackNotification;
use App\Rules\BrandIdentity;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Notification;
use Illuminate\Support\Facades\Validator;
use Illuminate\Validation\Rule;

class Controller extends BaseController
{
    use AuthorizesRequests;

    /**
     * Create a new controller instance.
     *
     * @return void
     */
    public function __construct() {
        $this->middleware('whmcs');
    }

    public function provision(Request $_r) {
        
        // Check whether head user exists.
        if($owner = User::where('email', '=', $_r->input('email'))->first()) {
            // Don't do anything - Duplicate purchase. Longterm we'll do something else here though.
        }
        else {
            // Provision an entirely new organisation, user, and organisation attributes.
            $outcome = DB::transaction(function () use($_r) {
                
                // Reserve things to keep it easy
                $organisation_name = $_r->input('organisation.name') ?? $_r->input('user.name');
                
                $user_email = $_r->input('user.email');
                $user_name = $_r->input('user.name');

                $user_group = Group::where('name', '=', 'Goliath Beta User')->first()->id;
                
                $billing_identifiers = [
                    $_r->input('billing.source', 'gsl') => $_r->input('billing.id', null)
                ];

                // Create the organisation
                $organisation_id = Organisation::create([
                    'name' => $organisation_name,
                    'billing' => $billing_identifiers
                ])->id;

                // Create the head user
                $user = new User([
                    'name'              => $user_name,
                    'password'          => '',
                    'email'             => $user_email,
                    'group_id'          => $user_group,
                    'organisation_id'   => $organisation_id
                ]);

                // Create the organisational attributes
                MercuryOrganisationAttributes::create([
                    'organisation_id' => $organisation_id,
                    'allow_high' => false,
                    'allow_announcements' => true,
                    'allow_downstreaming' => false
                ]);

                GoliathOrganisationAttributes::create([
                    'organisation_id' => $organisation_id
                ]);

                if($user->save()) {
                    
                    $user->sendSetupEmail();

                    Notification::route('slack', config('creatia.webhook.standard'))->notify(new SlackNotification("Account has been provisioned successfully. Company: $organisation_name, Name: $user_name, Email: $user_email"));

                    return true;
                }

                return false;
            });

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

    public function provision_dedi(Request $_r) {

        $valid_request = !Validator::make([
            
            // Organisation
            'organisation'      => $_r->input('organisation'),
            'identifiers'       => $_r->input('identifiers'),
            'subtenant'         => $_r->input('subtenant'),

            // User
            'email'             => $_r->input('email'),
            'owner'             => $_r->input('owner'),
            
        ], [

            // Organisation
            'organisation'           => ['required', 'string'],
            'identifiers.*.key'      => ['required', 'string'],
            'identifiers.*.identity' => ['required', 'string'],
            'subtenant'              => ['required', new BrandIdentity],

            // User
            'email'             => ['required', 'email:rfc,dns'],
            'owner'            => ['required', 'string'],

        ])->fails();

        if(!$valid_request) {
            return response()->json(['detail' => 'Bad payload.'], 400);
        }

        // Check whether head user exists.
        if($owner = User::where('email', '=', $_r->input('email'))->first()) {
            // Don't do anything - Duplicate purchase. Longterm we'll do something else here though.
        }
        else {

            /**
             * Create Organisation First
             */

            $organisation_id = null;

            $suffix = $_r->input('subtenant') === 'go-dedicated' ? '[DEDI-GD]' : ( $_r->input('subtenant') === 'streamline' ? '[DEDI-SL]' : '[DEDI]' );
            
            try {

                DB::beginTransaction();

                // To create an organisation, you must provide ONE external identifier 
                $organisation_id = Organisation::create([
                    'name' => $_r->input('organisation') . ' ' . $suffix
                ])->id;

                // Create external identifiers
                $external_ids = [];

                $check_valid_query = OrganisationExternalIdentities::select('key', 'identity');

                foreach($_r->input('identifiers') as $x) {
                    $external_ids[] = [
                        'key'               => $x['key'],
                        'identity'          => $x['identity'],
                        'organisation_id'   => $organisation_id
                    ];

                    $check_valid_query = $check_valid_query->orWhere(function($q) use($x) { $q->where([['key', '=', $x['key']], ['identity', '=', $x['identity']]]); });
                }

                if($check_valid_query->count() === 0) {

                    if($external_ids !== []) {
                        OrganisationExternalIdentities::insert($external_ids);
                    }

                    MercuryOrganisationAttributes::create([
                        'organisation_id'           => $organisation_id,
                        'allow_high'                => false,
                        'allow_announcements'       => true,
                        'allow_downstreaming'       => false
                    ]);

                    GoliathOrganisationAttributes::create([
                        'organisation_id' => $organisation_id
                    ]);

                    if($_r->input('subtenant', false)) {
                        switch($_r->input('subtenant')) {
                            case 'go-dedicated':
                                Suborganisation::create([
                                    'parent_id' => Organisation::where('name', '=', 'Go Dedicated')->orderBy('id', 'asc')->first()->id,
                                    'child_id'  => $organisation_id
                                ]);
                                break;
                            case 'streamline':
                                Suborganisation::create([
                                    'parent_id' => Organisation::where('name', '=', 'Streamline Servers')->orderBy('id', 'asc')->first()->id,
                                    'child_id'  => $organisation_id
                                ]);
                                break;
                        }
                    }

                    Notification::route('slack', config('creatia.webhook.standard'))->notify(new SlackNotification("DEDI Organisation has been provisioned successfully. Company: " . $_r->input('organisation') . "$suffix (ORG-$organisation_id)"));

                    DB::commit();
                }
            }
            catch(\Exception $ex) {
                DB::rollback();

                Notification::route('slack', config('creatia.webhook.standard'))->notify(new SlackNotification("DEDI Organisation has failed to provision successfully. Company: " . $_r->input('organisation') . $suffix));

                return response()->json(['detail' => 'Failed to make organisation.'], 500);
            }

            /**
             * Create User
             */

            try {

                $user_email = $_r->input('email');
                $user_name = $_r->input('owner');

                $user = new User([
                    'name'              => $user_name,
                    'password'          => '',
                    'email'             => $user_email,
                    'group_id'          => Group::where('name', '=', 'Creatia Read-Only User')->first()->id,
                    'organisation_id'   => $organisation_id
                ]);

                if($user->save()) {

                    $user->sendSetupEmail();

                    Notification::route('slack', config('creatia.webhook.standard'))->notify(new SlackNotification("DEDI Account has been provisioned successfully. Company: " . $_r->input('organisation') . "$suffix, Name: $user_name, Email: $user_email"));

                }
            }
            catch(\Exception $ex) {
                Notification::route('slack', config('creatia.webhook.standard'))->notify(new SlackNotification("DEDI User has failed to provision successfully. Company: " . $_r->input('email')));

                \Log::debug($ex);

                return response()->json(['detail' => 'Failed to make user.'], 500);
            }

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

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

    public function terminate_account(Request $_r) {
        // Mark users as deleted, then organisation, then prefixes - Then free up the ASN back to GSL. Magical.

    }
}
