<?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\EmailPricing;
use App\Http\Controllers\Controller;
use App\MediaPrice;
use App\Network;
use App\Role;
use App\Tools\CreditTool;
use App\Tools\SmsTools;
use App\User;
use App\UserCurrency;
use App\UserMailSubscription;
use App\UserSenderId;
use App\UserSocialSubscription;
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 ?? 0;
        $email_price = Auth::user()->credit->email_price ?? 0;
        $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',
                'mobile_money_number' => 'sometimes|nullable|digits_between:10,20',
                'company_phone_number' => 'sometimes|nullable|digits_between:10,20',
                'business_logo' => 'sometimes|nullable',
                'sms_price' => 'required',
                'contact_person' => 'required',
                'nature_of_business' => 'required',
                'contact_person_id' => 'sometimes|nullable',
                'contact_person_designation' => 'sometimes|nullable',
                //                'contact_person_phone' =>'required|unique:companies|digits_between:10,20',
                'contact_person_phone' => 'required|digits_between:10,20',
                'contact_person_email' => 'required',
                'username' => 'required|min:6|unique:users',

            ]
        );
        try {
            $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();




            /** 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['company_phone_number'] = 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');
            $records['contact_person_phone'] = SmsTools::format_gh_number($request->input('contact_person_phone'));

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

            DB::beginTransaction();

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

            if ($user):

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

                $user->credit()->create([
                    'username' => $user->username,
                    'price' => $request->input('sms_price') ?? '0.024',
                    'email_price' => '0.00332',
                    'credit_alloted' => '0.00',
                    'old_bal' => '0',
                    'new_bal' => '0.00',
                    'credit_used' => '0',
                    'credited' => '0'
                ]); // create the user details for the company or individual
                $output = $this->saveFiles($request); // save files
                $output['business_logo'] = auth()->user()->company->business_logo;
                $company = Company::query()->create($records); //create the company
                $company->putToTrialMode($records); //put to trial mode
                $company->update($output); // update company records with the files captured


                $balance = $user->credit->price * 3;
                $user->credit->update(['new_bal' => $balance, 'credited' => $balance]);


                if ($company):

                    $user->update(['company_id' => $company->id]); //update user table with company table

                    if (isset($sendor_ids))
                        $this->saveSenderId($sendor_ids, $user); //then we save the sender Id here

                    if (isset($directors))
                        $this->saveDirectors($directors, $company); //we save the company's director here

                    $status = $this->setStatus($company); //sets the company to approved

                    $company->update($status); //updates the company status to approved


                    $data['email'] = $user->email;
                    $data['name'] = $user->full_name;
                    $data['c_username'] = $user->username;
                    $data['c_password'] = $user->pass;
                    $data['url'] = route($result['url']);
                    $data['content'] = "Your account for Deywuro has been created and register under {$user->created_by} with username and password";


                    try {
                        Mail::send('emails.admin_login', $data, function ($m) use ($data) {
                            $m->from('sms@deywuro.com', 'Deywuro');
                            $m->to($data['email'], $data['name']);
                            $m->subject('Company Registration');
                        });
                    } catch (\Exception $e) {
                    }


                    try {
                        Mail::send('emails.admin_login', ['company' => $company, 'reseller' => auth()->user()], function ($m) {
                            $m->from('sms@deywuro.com', 'Deywuro');
                            $m->to('support@npontu.com');
                            $m->subject('New Company Registration');
                        });
                    } catch (\Exception $ex) {
                    }


                    // $msg = "Hello {$company->name},
                    // Your account for Deywuro has been created with username and password
                    // username : {$company->users->username}
                    // password : {$company->users->pass}
                    // registered under: {$company->users->created_by}
                    // url : {$data['url']}
                    // Thank You,
                    // Deywuro";
                    $msg = "Hello {$company->name},\n\n" .
                        "Your account for Deywuro has been created.\n" .
                        "Username: {$company->users->username}\n" .
                        "Password: {$company->users->pass}\n" .
                        "Registered under: {$company->users->created_by}\n" .
                        "URL: {$data['url']}\n\n" .
                        "Thank you,\nDeywuro";

                    $this->sendSms($msg, $company->users->phone_number);

                endif;
            endif;

            DB::commit();
        } catch (\Exception $ex) {
            $this->appLog("RESELLER CREATE CLIENT {$ex->getMessage()}");
            return redirect()->back()->withErrors('Request Could not be processed kindly try again');
        }

        return redirect()->route('reseller.users')->with('success', "Client Successfully Registered. Request ID is {$status['code']}");
    }

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

        // reseller
        $reseller = Auth::user();
        return view('reseller.users.new_user_payment', ['record' => $record, 'reseller' => $reseller]);
    }

    public function check_reseller_balance(Request $request, $id)
    {

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

        $client_credit = $user->credit;

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

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

        //the $user here is the same as the client being credited;
        $C = $amount / $client_credit->price; //derived from amount being credited to the client and the unit price being set for the client

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

        $T = $R - $C;


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

        //        if($amount > $reseller->new_bal)

        if ($balance < 0) {
            $amount_to_topup = abs($balance);
            return response()->json([
                'status' => 'failed',
                'new_bal' => $balance,
                'message' => "Kindly top up with $amount_to_topup or more"
            ]);
        }

        return response()->json([
            'status' => 'success',
            'new_bal' => $balance,
            'message' => "Kindly proceed to credit your client"
        ]);
    }

    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]);
    }


    public function user_email_payment(User $user)
    {

        $packages = auth()->user()->email_pricing()->where('is_active', true)->get();
        return view('reseller.users.subscription', compact('packages', 'user'));
    }

    public function user_email_signup(User $user, EmailPricing $package)
    {
        $expires_on = Carbon::parse(now())->addDays(30);

        DB::beginTransaction();

        UserMailSubscription::query()->updateOrCreate(
            ['user_id' => $user->id],
            [
                'is_paid' => true,
                'expires_on' => $expires_on,
                'email_pricing_id' => $package->id
            ]
        );


        \auth()->user()->trail("SIGNUP USER $user->username on $package->name");
        DB::commit();

        return redirect()->route('reseller.users')->with('success', 'User Successfully signed up');
    }

    public function user_social_payment(User $user)
    {

        $packages = auth()->user()->media_price()->where('is_active', true)->get();
        return view('reseller.users.social_subscription', compact('packages', 'user'));
    }

    public function user_social_signup(User $user, MediaPrice $package)
    {
        $expires_on = Carbon::parse(now())->addDays(30);

        DB::beginTransaction();

        UserSocialSubscription::query()->updateOrCreate(
            ['user_id' => $user->id],
            [
                'is_paid' => true,
                'expires_on' => $expires_on,
                'media_price_id' => $package->id
            ]
        );


        auth()->user()->trail("SIGNUP USER $user->username on SOCIAL MEDIA PACK. $package->name");

        DB::commit();

        return redirect()->route('reseller.users')->with('success', 'User Successfully signed up');
    }







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

        //the $user here is the same as the client being credited
        $amount = -1 * $amount;

        $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

        $amount = -1 * $amount;

        //        if($amount > $reseller->new_bal)

        if ($balance < 0)
            return false;

        // Round up reseller balance and convert to string
        // Converting to string makes possible to insert decimal part of a number
        $balance = (string) round($balance, 3);

        //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 = (string) round(($client->new_bal + $amount), 3);
        $client->credited = (string) $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' => (string) $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_old($id)
    {
        $user = Auth::user();
        $record = User::with('credit')->where([
            ['created_by', '=', $user->username]
        ])->findOrFail($id);
        return view('reseller.users.edit', ['record' => $record]);
    }

    public function edit_user(Request $request, $id)
    {
        $company = User::query()->find($id)->company;
        $sends = json_encode(UserSenderId::query()->where('user_id', $company->users->id)->select('id', 'sender_id as name')->get()->toArray());
        $dirs = json_encode($company->directors()->select('id', 'name', 'designation')->get()->toArray());


        if ($request->isMethod('Post')):

            $this->validate($request, [
                //                'date_of_incorporation' =>'required',
                //                'legal_status' =>'required',
                'nature_of_business' => 'required',
                'name' => 'required|unique:companies,name,' . $company->id,
                'company_phone_number' => 'required|digits_between:10,20',
                'contact_person' => 'required',
                'sms_price' => 'required',
                'contact_person_phone' => 'required|digits_between:10,20',
                'contact_person_email' => 'required',
            ]);

            $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 && $company->users->email != $verify->email)
                return redirect()->back()->withInput(Input::all())->withErrors('the email ' . $request->input('contact_person_email') . ' has already been taken');

            $records = $request->all();


            $result = $this->editUserInfo($request);


            DB::beginTransaction();

            if (!empty($company->users))
                $user = $company->users->update($result);

            $company->users->credit->update(['price' => $request->input('sms_price')]);

            $company->update($records);


            $output = $this->editSavedFiles($request, $company);
            if (!empty($output))
                $company->update($output);

            DB::commit();

            return redirect()->route('reseller.users')->with('success', 'Company Successfully Updated');

        endif;


        return view('reseller.users.edit', compact('company', 'sends', 'dirs'));
    }

    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();
    }
}
