<?php /** @noinspection PhpUndefinedMethodInspection */

namespace App\Http\Controllers\Reseller;

use App\AdminAccessRight;
use App\Company;
use App\Credit;
use App\CreditHistory;
use App\Currency;
use App\DataTables\ResellerUserDataTable;
use App\DataTables\ResellerUserPaymDataTable;
use App\Http\Controllers\Controller;
use App\Network;
use App\Role;
use App\Tools\CreditTool;
use App\Tools\SmsTools;
use App\User;
use App\UserCurrency;
use Carbon\Carbon;
use Illuminate\Http\Request;

use App\Http\Requests;
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Input;
use Illuminate\Support\Facades\Log;
use Illuminate\Support\Facades\Mail;
use Illuminate\Support\Str;
use App\Opt\ResellerClientTrait;

class UserController extends Controller
{

    use ResellerClientTrait;
    private $ctool;

    public function __construct(CreditTool $tool)
    {
        $this->ctool = $tool;
    }

    public function user_networks($user_id) {
        $user = User::where([
            ['created_by', '=', Auth::user()->username]
        ])->findOrFail($user_id);
        $data = [];
        foreach (Network::with('country')
                     ->orderBy('country_id')
                     ->orderBy('nice_name')
                     ->get( ) as $record) {
            $existing = $user->user_networks()->where([
                ['network_id', '=', $record->id],
                ['country_id', '=', $record->country_id]
            ])->first();
            $data[] = [
                'id' => $record->id,
                'full_name' => $record->full_name,
                'nice_name' => $record->nice_name,
                'code' => $record->code,
                'country_id' => $record->country_id,
                'country' => $record->country->name,
                'prefix' => $record->prefix,
                'sms_price' => empty($existing) ? $record->sms_price : $existing->sms_price
            ];
        }
        return view('reseller.users.user_networks', ['data'=>$data, 'user'=>$user]);
    }

    public function edit_user_network($user_id, $id) {
        $user = User::where([
            ['created_by', '=', Auth::user()->username]
        ])->findOrFail($user_id);
        $global_network = Network::findOrFail($id);
        $user_network = $user->user_networks()
            ->where('network_id', $global_network->id)
            ->where('country_id', $global_network->country_id)
            ->first();
        $record = [
            'id' => $global_network->id,
            'full_name' => $global_network->full_name,
            'nice_name' => $global_network->nice_name,
            'code' => $global_network->code,
            'country_id' => $global_network->country_id,
            'country' => $global_network->country->name,
            'prefix' => $global_network->prefix,
            'sms_price' => empty($user_network) ? $global_network->sms_price : $user_network->sms_price
        ];

        return view('reseller.users.edit_user_network', [
            'user' => $user,
            'record' => $record
        ]);

    }

    public function update_user_network(Request $request, $user_id, $id) {
        $this->validate($request, [
            'sms_price' => 'required|numeric'
        ]);

        $user = User::where([
            ['created_by', '=', Auth::user()->username]
        ])->findOrFail($user_id);
        $global_network = Network::findOrFail($id);
        $user_network = $user->user_networks()
            ->where('network_id', $global_network->id)
            ->where('country_id', $global_network->country_id)
            ->first();

        //get owner price
        $owner_network = auth()->user()->user_networks()
            ->where('network_id', $global_network->id)
            ->where('country_id', $global_network->country_id)
            ->first();

        $owner_price = empty($owner_network) ? $global_network->sms_price : $owner_network->sms_price;
        $new_price = (float)$request['sms_price'];

        //check that price is valid!
        if($new_price < $owner_price) {
            return redirect()->back()->withInput()->withErrors(array('sms_price' => 'You cannot set a price below '.$owner_price));
        }

        if(!empty($new_price)) {
            if(!empty($user_network)) {
                $user_network->update(['sms_price'=>"$new_price"]);
            } else {
                if((float)$new_price !== (float)$global_network->sms_price) {
                    $user->user_networks()->create([
                        'network_id'  => $global_network->id,
                        'country_id' => $global_network->country_id,
                        'sms_price' => "$new_price"
                    ]);
                }
            }
        } else {
            return redirect()->back()->withInput()->withErrors(array('error' => 'The network price is invalid'));
        }

        $request->session()->flash('success', 'The user network price was successfully updated!');
        return redirect()->route('reseller.users.networks', ['user_id'=>$user->id]);
    }

    public function index(ResellerUserDataTable $dataTable) {
        return $dataTable->render('reseller.users.index');
    }

    public function new_user() {
        $sms_price = Auth::user()->credit->price;
        $email_price = Auth::user()->credit->email_price;
        $currency = auth()->user()->currency;
        return view('reseller.users.new',[
            'sms_price' => $sms_price,
            'email_price' => $email_price,
            'currency' => $currency
        ]);
    }

    public function post_new_user(Request $request) {

            $this->validate($request,[
                'name' =>'required|unique:companies',
                'contact_person_email' =>'required|email',
                //'date_of_incorporation' =>'required',
                'legal_status' =>'required',
                'company_phone_number' =>'required|digits_between:10,20',
                'mobile_money_number' =>'required|digits_between:10,20',
                'contact_person' =>'required',
                'contact_person_designation' =>'required',
                'contact_person_phone' =>'required|digits_between:10,20',
            ]);

//            $contains = Str::contains($request->input('contact_person_email'), ['@']);
//
//            if(!$contains)
//                return redirect()->back()->withInput(Input::all())->withErrors('This is not a valid email');

            $verify = User::query()->where('email',$request->input('contact_person_email'))->first();

            if($verify)
                return redirect()->back()->withInput(Input::all())->withErrors('the email '.$request->input('contact_person_email').' has already been taken');

            $records = $request->all();



            $sendor_ids   = $request->has('sender_ids') ? json_decode($records['sender_ids'], true) : array();
            $directors   = $request->has('items') ?  json_decode($records['items'], true)   :  array();

            /** Check for null values on the sender IDs and the Directors */
//            if($sendor_ids == null  || $directors == null)
//                redirect()->back()->withErrors('All Fields Are Required');


            /** Validation check on company directors **/
//            if(count($directors) < 2)
//                return redirect()->back()->withInput(Input::all())->withErrors('Company directors field should have a Minimum of one director');

            /** IF OPTIONAL FIELDS ARE EMPTY INSERT N/A **/
            $records['nature_of_business'] = empty($request->input('nature_of_business')) ? 'N/A' : $request->input('nature_of_business');
            $records['location_in_other_countries'] = empty($request->input('location_in_other_countries')) ? 'N/A' : $request->input('location_in_other_countries');
            $records['physical_address'] = empty($request->input('physical_address')) ? 'N/A' : $request->input('physical_address');
            $records['postal_address'] = empty($request->input('postal_address')) ? 'N/A' : $request->input('postal_address');

            $result = $this->generateUserInfo($request);
            $result['created_by'] = Auth::user()->username ?? 'messenger';

        DB::beginTransaction();

            $user = User::query()->create($result);

            if($user):

                //create the user credit details
                $user->credit()->create([

                    'username' => $user->username,
                    'price' => '0.03',
                    'email_price' => '0.00332',
                    'credit_alloted' => '0.00',
                    'old_bal' => '0',
                    'new_bal' => '5.00',
                    'credit_used' => '0',
                    'credited' => '5.00'
                ]);

                $records['user_id'] = $user->id;


                $output  = $this->saveFiles($request);

                $company = Company::query()->create($records);

                $company->update($output);

                $company->putToTrialMode($records); //put to trial mode

                if($company):
                    //update user table with company table
                    $user->update(['company_id' => $company->id]);
                    //then we save the sender Id here
                    $this->saveSenderId($sendor_ids,$user);
                    // we save the company's director here
                    $this->saveDirectors($directors ?? [],$company);

                    $status = $this->setStatus($company);

                    $company->update($status);


                    try {

                        $url = 'https://mtnmessenger.com/login';
                        $msg = "Hello {$company->name},
Your account for the MTN Business Messenger has been created with username and password 
username : {$company->users->username}
password : {$company->users->pass}
url : {$url}
Thank You,
MTN MESSENGER";

                        $data['email']      = $company->users->email;
                        $data['name']       = $company->name;
                        $data['c_username'] = $company->users->username;
                        $data['c_password'] = $company->users->pass;
                        $data['url']        = $url;
                        $data['content']    = "Your account for the MTN Business Messenger has been created with username and password";

                        /** @noinspection PhpUndefinedClassInspection */
                        Mail::send('emails.admin_login', $data, function ($m) use ($data) {
                            $m->from('mtn@messenger.com', 'MESSENGER');
                            $m->to($data['email'],  $data['name']);
                            $m->subject('MTN MESSENGER');
                        });

                        $this->sendSms($msg, $company->users->phone_number);
                    }catch (\Exception $ex){}

                endif;
            endif;

            DB::commit();

            return redirect()->route('reseller.users')->with('success',"Client Successfully Registered. account will be verified and created within 2 working days. Request ID is {$status['code']}");

    }

    public function new_user_payment($id) {
        $record = User::where([
            ['created_by', '=', Auth::user()->username]
        ])->findOrFail($id);
        return view('reseller.users.new_user_payment', ['record'=>$record]);
    }

    public function mark_payment_as_paid($id) {
        $record = CreditHistory::query()->where([
            ['credited_by', '=', Auth::user()->username]
        ])->findOrFail($id);
        $record->status = 'paid';
        $record->save();
        session()->flash('success', 'The payment has been marked as paid');
        return redirect()->back();
    }

    public function post_user_payment(Request $request, $id) {
        $user = User::with('credit')->where([
            ['created_by', '=', Auth::user()->username]
        ])->findOrFail($id);

        $user_credit = $user->credit;

        $this->validate($request, [
            'credited' => 'required|numeric',
            'status' => 'required'
        ]);

        //get first name and last name
        $owner = Auth::user();

        DB::beginTransaction();

            $cred_add = $request['credited'];
            $reseller_credit = $owner->credit;

       $output = $this->credit_that_guy($reseller_credit,$user_credit,$cred_add,$user,$request,$owner);

        if(!$output)
            return redirect()->back()->withInput()->withErrors(array('error' => 'You do not have enough balance to perform this transaction'));


        DB::commit();

        //send email to client
        if(1) {
            //prepare data to pass to email view
            $data = [
                'currency' => $user->currency,
                'amount' => $request['credited'],
                'credited_by' => Auth::user()->username,
                'full_name' => $user->full_name,
                'org' => (!empty($owner->organisation) ? $owner->organisation: ' the SMS Platform')
            ];
            //send email notification to client
            try {
                Mail::send('emails.credit_account_msg', $data, function ($m) use ($user, $owner) {
                    $m_email = $owner->email ?: 'support@npontu.com';
                    $m->from($m_email, (!empty($owner->organisation) ? $owner->organisation : 'SMS Platform'));
                    $m->cc($owner->email);
                    $m->cc('finance@npontu.com', 'Npontu Finance Team');
                    $m->to($user->email, $user->full_name);
                    $m->subject('Your account has been credited!');
                });
            } catch (\Throwable $t) {
                Log::error($t->getTraceAsString());
            }

        }

        $request->session()->flash('success', 'The user account was successfully credited!');
        return redirect()->route('reseller.users.payments', ['id'=>$id]);
    }


    private function credit_that_guy($reseller,$client,$amount,$user,$request,$owner)
    {

        //the $user here is the same as the client being credited;

        $C = $amount / $client->price;   //derived from amount being credited to the client and the unit price being set for the client

        $R = $reseller->new_bal / $reseller->price;

        $T = $R - $C;


        $balance = $T * $reseller->price;   // gets the balance lef for the reseller

        if($amount > $reseller->new_bal)
                return false;

        //then we balance the reseller
        $reseller->credit_used += $reseller->new_bal -$balance;    // will be the $C as stated above
        $reseller->old_bal = $reseller->new_bal;
        $reseller->new_bal = $balance;
        $reseller->updated_by =  Auth::user()->username;
        $reseller->save();


        //then we balance client

        $client->credit_alloted +=  $amount;
        $client->old_bal =  $client->new_bal;
        $client->new_bal +=  $amount;
        $client->credited =  $amount;
        $client->updated_by =  Auth::user()->username;
        $client->save();


//        dd($reseller,$client,$balance);



        /** then we update the credit history of the client */

        $user->creditHistory()->create([
            'status' => $request['status'],
            'date_credited' => Carbon::now()->toDateTimeString(),
            'username' => $user->username,
            'price' => $client->price,
            'credit_alloted' => $client->credit_alloted,
            'old_bal' => $client->old_bal,
            'new_bal' => $client->new_bal,
            'credit_used' => $client->credit_used,
            'credited' => $amount,
            'credited_by' => Auth::user()->username,
            'comments' => $user->username.' has been credited by '. Auth::user()->username.' with '.$client->new_bal
        ]);


        $owner->creditHistory()->create([
            'date_credited' => Carbon::now()->toDateTimeString(),
            'username' => $owner->username,
            'price' => $reseller->price,
            'credit_alloted' => $reseller->credit_alloted,
            'old_bal' => $reseller->old_bal,
            'new_bal' => $reseller->new_bal,
            'credit_used' => $reseller->credit_used,
            'credited' => $reseller->credited,
            'credited_by' => $owner->username,
            'comments' => $owner->username.' has credited user '.$user->username.' with '.$amount,
        ]);


        return true;

    }

    public function lock_user($id) {
        $record = User::query()->where([
            ['created_by', '=', Auth::user()->username]
        ])->findOrFail($id);

        $record->is_locked = !$record->is_locked;
        $record->save();

        session()->flash('success', 'The user was successfully '.($record->is_locked ? 'locked':'unlocked!'));
        return redirect()->route('reseller.users', ['id'=>$id]);
    }

    public function user_payments($id, ResellerUserPaymDataTable $dataTable) {
        $record = User::where([
            ['created_by', '=', Auth::user()->username]
        ])->findOrFail($id);

        return $dataTable->render('reseller.users.payment', ['record'=> $record]);
    }

    public function edit_user($id) {
        $user = Auth::user();
        $record = User::with('credit')->where([
            ['created_by', '=', $user->username]
        ])->findOrFail($id);
        return view('reseller.users.edit', ['record'=>$record]);
    }

    public function update_user(Request $request, $id) {
        $this->validate($request, [
            'contact_person' => 'required|max:255',
//            'password' => 'present',
//            'password_confirmation' => 'same:password',
            'email' => 'required|email|unique:users,email,'.$id,
            'phone_number' => 'required|digits_between:9,16',
            'price' => 'required|numeric',
            'email_price' => 'required|numeric',
        ]);

        $record = User::with('credit')->where([
            ['created_by', '=', Auth::user()->username]
        ])->findOrFail($id);

        //get first name and last name
        $inputs = $request->except(['password']);
        $parts = explode(" ", $request['contact_person']);
        $inputs['first_name'] = array_pop($parts);
        $inputs['last_name'] = implode(" ", $parts);
        $inputs['full_name']= $request['contact_person'];

        //format the phone number
        $inputs['phone_number'] = SmsTools::format_gh_number($request->get('phone_number'));

        //encrypt the password
        if(!empty($request['password'])) {
            $inputs['password'] = bcrypt($request['password']);
            $inputs['pass'] = $request['password'];
            $inputs['status'] = 'active';
            $inputs['is_locked'] = false;
            $inputs['wrong_password_attempt_count'] = 0;
        }

        //set the user role
        $role = Role::where('name', 'user')->firstOrFail();
        $inputs['role_id'] = $role->id;

        $price = $request['price'];
        $reseller_price = auth()->user()->credit->price;
        if($price < $reseller_price) {
            return redirect()->back()->withInput()->withErrors(array('error' => 'You cannot set the sms price below '.$reseller_price));
        }
        $email_price = $request['email_price'];
        $reseller_email_price = auth()->user()->credit->email_price;
        if($email_price < $reseller_email_price) {
            return redirect()->back()->withInput()->withErrors(array('error' => 'You cannot set the email price below '.$reseller_email_price));
        }

        //update the client
        DB::beginTransaction();
        $record->update($inputs);
        $record->credit->update([
            'price' => $price,
            'email_price' => $email_price,
        ]);
        DB::commit();

        $request->session()->flash('success', 'The user was successfully updated!');
        return redirect()->route('reseller.users');
    }

    public function delete_user($id) {
        $user = Auth::user();
        $record = User::with('credit')->where([
            ['created_by', '=', $user->username]
        ])->findOrFail($id);

        $record->delete();
        session()->flash('success', 'The user "'.$record->username.'" was successfully deleted!');
        return redirect()->back();
    }
}
