<?php

namespace App\Http\Controllers;

use App\AppBlocks;
use App\iSession;
use App\Jobs\NewMemberInit;
use Carbon\Carbon;
use Illuminate\Database\QueryException;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Artisan;
use Illuminate\Support\Facades\Cache;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Hash;
use Illuminate\Support\Facades\Log;
use Illuminate\Support\Facades\Mail;
use Illuminate\Support\Facades\Response;
use Illuminate\Support\Facades\Validator;
use Illuminate\Support\Str;
use Yajny\Controller\BrandCtrl;
use Yajny\MailYj\Mails\VerifyEmail;
use Yajny\MailYj\Mails\WelcomeVerifiedUser;
use Yajny\Member\Models\BonusType;
use Yajny\Member\Models\Currencies;
use Yajny\Member\Models\Member;
use Yajny\Models\Country;
use Yajny\Models\Event;
use Yajny\Models\Region;

class AppController extends Controller
{
    /**
     * Create a new controller instance.
     *
     * @return void
     */
    public function __construct()
    {
        //
    }

    /**
     * @return \Illuminate\Http\JsonResponse
     */
    public function forceUpdate()
    {
        return Response::json([], 426);
    }

    /**
     * @return mixed
     */
    public function getHomeScreens()
    {

        return AppBlocks::selectRaw(AppBlocks::colSelect())->where('purpose', 'welcome')->where('is_shown', 1)->orderBy('sort_order')->get();
    }

    /**
     * @param Request $request
     * @return array|bool[]
     */
    public function deleteAccountForDev(Request $request)
    {

        $email= $request->get('email') ?? '';

        if($email!=''){
            $member= Member::where('email',$email)->first();
            $member->delete();
            return ['deleted'=>true];
        }
        return ['deleted'=>false,'account'=> "not found"];
    }
    /**
     * @param Request $request
     * @return array
     */
    public function updateSessLang(Request $request)
    {

        $session = iSession::find($request->web_token);
        $payload = unserialize(base64_decode($session->payload));
        $payload['lang'] = $request->lang;
        $payload['region'] = $request->region ?? null;
        $session->payload = base64_encode(serialize($payload));
        $session->save();
        return ['web_token' => $request->web_token, 'token' => $request->token];
    }

    /**
     * @param Request $request
     * @return array
     */
    public function logout(Request $request)
    {
        $session = iSession::find($request->web_token);
        if ($session)
            $session->delete();

        return $this->getToken($request);
    }

    /**
     * @param Request $request
     * @return array
     */
    public function getToken(Request $request)
    {

        $sess_id = Str::random(30) . time();
        $token = Str::random(40);
        $payload = [
            'user_id' => '0',
            'lang' => $request->lang,
            'region' => $request->region ?? null,
            '_token' => $token
        ];
        $session = [
            'id' => $sess_id,
            'user_id' => 0,
            'ip_address' => $request->ip(),
            'user_agent' => $request->userAgent(),
            'last_activity' => time(),
            'payload' => base64_encode(serialize($payload))
        ];

        $sess = new iSession($session);
        $sess->save();

        return ['web_token' => $sess_id, 'token' => $token];
    }

    /**
     * @param Request $request
     * @return array
     */
    public function updateSessionInfo(Request $request)
    {
        Validator::make($request->all(), [
            'user_id' => 'required',
            'lang' => 'required',
            'token' => 'required',
            'web_token' => 'required',
        ])->validate();
        $payload = [
            'user_id' => $request->user_id,
            'lang' => $request->lang,
            '_token' => $request->token
        ];

        //handle duplicate entry
        try {
            iSession::updateOrCreate(['id' => $request->web_token],
                [
                    'ip_address' => $request->ip(),
                    'user_agent' => $request->userAgent(),
                    'user_id' => $request->user_id,
                    'last_activity' => time(),
                    'payload' => base64_encode(serialize($payload))
                ]);
        } catch (QueryException $e) {
            if (isset($e->errorInfo[1]) && $e->errorInfo[1] === 1062) {
                iSession::where('id', $request->web_token)->update([
                    'ip_address' => $request->ip(),
                    'user_agent' => $request->userAgent(),
                    'user_id' => $request->user_id,
                    'last_activity' => time(),
                    'payload' => base64_encode(serialize($payload))
                ]);
            } else {
                throw $e;
            }
        }
        return ['web_token' => $request->web_token, 'token' => $request->token];
    }

    // TODO: To Be Removed in new Release

    /**
     * @param Request $request
     * @return array|\string[][]
     */
    public function login(Request $request)
    {
        $validator = Validator::make($request->all(), [
            'email' => 'required|email|exists:users,email'
        ]);

        if ($validator->fails()) {
            return ['errors' => $validator->errors()];
        }

        $member = Member::where('email', $request->email)->first();
        if (!$member) return ['errors' => ['email' => 'No user with that email']];

        if (Hash::check($request->password, $member->password)) {
            return $this->commonLoginUser($member, $request->web_token);
        } else
            return ['errors' => ['email' => 'Wrong Password', 'password' => 'Wrong Password',]];
    }

    // TODO: To Be Removed in new Release

    /**
     * @param Request $request
     * @return mixed
     */
    public function socialLogin(Request $request)
    {
        if (!isset($request->email) || empty($request->email) || $request->email == 'undefined') {
            Log::debug('Facebook undefined email issue Mobile', $request->all());
        }

        Validator::make($request->all(), [
            'gender' => 'sometimes|in:Male,Female'
        ])->validate();

        $member = Member::where('email', $request->email)->first();
        if ($member) {
            if (empty($member->gender)) {
                $member->gender = $request->gender ?? null;
            }

            if (empty($member->photo)) {
                $member->photo = $request->photo ?? null;
            }

            $member->save();
            return $this->commonLoginUser($member, $request->web_token);
        } else {
            return $this->commonCreateUser($request);
        }
    }

    // TODO: To Be Removed in new Release

    /**
     * @param $member
     * @param $web_token
     * @return mixed
     */
    public function commonLoginUser($member, $web_token)
    {
        $session = iSession::find($web_token);
        $payload = unserialize(base64_decode($session->payload));
        $payload['user_id'] = $member->user_id;
        $session->user_id = $member->user_id;
        $session->payload = base64_encode(serialize($payload));
        $session->save();

        if (!$member->gender)
            $member->gender = '';
        return $member;
    }

    // TODO: To Be Removed in new Release

    /**
     * @param Request $request
     * @return array|mixed|\string[][]
     */
    public function registerUser(Request $request)
    {
        $validator = Validator::make($request->all(), [
            'email' => 'required|email',
            'password' => 'required|min:8',
        ]);

        if ($validator->fails()) {
            return ['errors' => $validator->errors()];
        }

        $member = Member::where('email', $request->email)->first();
        if ($member) {
            return ['errors' => ['email' => 'User Already Exists']];
        } else {
            return $this->commonCreateUser($request);
        }
    }

    // TODO: To Be Removed in new Release

    /**
     * @param Request $request
     * @return mixed
     */
    public function commonCreateUser(Request $request)
    {
        Validator::make($request->all(), [
            'gender' => 'sometimes|in:Male,Female',
            'email' => 'required|email:rfc,dns,filter'
        ])->validate();
        $createUser = [
            'email' => $request->email,
            'first_name' => strstr($request->email, '@', true),
            'last_name' => '',
            'password' => Hash::make($request->password),
            'active' => 1, 'signup_via' => $request->platform,
            'social_id' => $request->social_id,
            'referral_code' => substr(str_shuffle("0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"), 0, 5),
            'email_verified_at' => ($request->platform == 'email') ? null : date('Y-m-d H:i:s'),
            'user_lang' => isset($request->lang) ? $request->lang : 'en',
            'region_code'=>null
        ];

        if ($request->photo) {
            $createUser['photo'] = $request->photo;
        }

        if ($request->gender) {
            $createUser['gender'] = $request->gender;
        }

        $createUser['platform'] = $request->header('platform');
        if (isset($request->refcode) && preg_match("/^[a-zA-Z0-9]*$/", $request->refcode))
            $createUser['referrer_code'] = substr(trim($request->refcode), 0, 5);

        $member = Member::create($createUser);
        if ($request->platform == 'email')
            Mail::to($member->email)->locale($member->user_lang)->queue(new VerifyEmail($member));
        else
            Mail::to($request->email)->locale($request->lang)->queue(new WelcomeVerifiedUser($member));

        // after user register actions
        NewMemberInit::dispatch($member)->onQueue('default');
        return $this->commonLoginUser($member, $request->web_token);
    }

    // TODO: To Be Removed in new Release

    /**
     * @param Request $request
     * @return string[]|\string[][]
     */
    public function forgotPassword(Request $request)
    {

        $member = Member::where('email', $request->email)->first();
        if (!$member)
            return ['errors' => ['email' => 'There is no account with that email']];

        \Illuminate\Support\Facades\Mail::to($member->email)->locale($member->user_lang)->send((new \Yajny\MailYj\Mails\PasswordResetOTP($member, $request->otp)));

        return ['sent' => 'yes'];
    }

    // TODO: To Be Removed in new Release

    /**
     * @param Request $request
     * @return string[]|\string[][]
     */
    public function resetPassword(Request $request)
    {

        $member = Member::where('email', $request->email)->first();
        if (!$member)
            return ['errors' => ['email' => 'There is no account with that email']];

        $member->password = Hash::make($request->new_password);
        $member->save();
        /** TODO: Send Notice of password cahnge */
        return ['updated' => 'yes'];
    }

    /**
     * @return array
     */
    public function getLeaderboard()
    {
        return [
            'allTimeUsers' => $this->mapUserLeaderboard(Member::getAllTimeUserLeaderboard()),
            'thisMonthUsers' => $this->mapUserLeaderboard(Member::getThisMonthUserLeaderboard())
        ];
    }

    /**
     * @param $usersLeaderboard
     * @return array
     */
    private function mapUserLeaderboard($usersLeaderboard)
    {
        $mappedData = [];
        $rank = 1;
        foreach ($usersLeaderboard as $user) {
            $mappedData[] = [
                'name' => "{$user->user->first_name} {$user->user->last_name}",
                'photo' => $user->user->photoURL,
                'rank' => $rank++
            ];
        }
        return $mappedData;
    }

    // TODO: Refactor

    /**
     * @return \Illuminate\Database\Eloquent\Collection|Region[]
     */
    public function getRegions()
    {
        return Region::all();
    }

    // TODO: Refactor

    /**
     * @return mixed
     */
    public function getCountries()
    {
        return Country::select(['name', 'code'])->where('active', 1)->get();
    }

    // TODO: Refactor

    /**
     * @return \Illuminate\Database\Eloquent\Collection|BonusType[]
     */
    public function getBonuses()
    {
        $allCurrencies = Cache::rememberForever('currencies', function () {
            return Currencies::all()->mapWithKeys(function ($currency) {
                return [$currency->iso_code => $currency];
            });
        });
        $currency_code = request('userCurrency', 'USD');
        if (isset($allCurrencies[$currency_code]))
            $currency = $allCurrencies[$currency_code];
        else
            $currency = $allCurrencies['USD'];
        return BonusType::all()->mapWithKeys(function ($bonusType) use ($currency) {
            $bonusType->applyCurrencyConversion($currency);
            return [$bonusType->code => $bonusType];
        });
    }

    /**
     * @return array
     */
    public function getInitialData()
    {
        return [
            'regions' => $this->getRegions(),
            'countries' => $this->getCountries(),
            'bonuses' => $this->getBonuses(),
            'country_dial_codes' => $this->getDialCodes()
        ];
    }

    /**
     * @return mixed
     */
    public function getDialCodes()
    {
        return Country::where('for_otp', 1)->where('active', 1)->get()->map(function ($item) {
            return [
                'code' => $item->code,
                'dial_code' => $item->dial_code,
                'valid_length' => $item->valid_length
            ];
        });
    }

    /**
     * @return array
     */
    public function initData()
    {
        $user = null;
        if ($user_id = request('user_id')) {
            $user = Member::find($user_id);
        }

        $data = [
            'menu_items' => [],
            'user' => $user
        ];

        $dynamicEvents = Event::all();
        foreach ($dynamicEvents as $event) {
            if ($event->app_status && $event->has_menu_item) {
                $data['menu_items'][] = [
                    'slug' => $event->slug,
                    'name' => $event->getTranslations('name')
                ];
            }
        }

        return $data;
    }

    /**
     * @param Request $request
     * @return \Illuminate\Http\JsonResponse
     */
    public function test_amazon_orders(Request $request)
    {
        set_time_limit(0);
        $start_days = $request->start_days;
        $end_days = $request->end_days;

        if (is_null($start_days) || is_null($end_days))
            return \response()->json('Missing Input');

        Artisan::call("amazon:heal {$start_days} {$end_days} -s");
        return \response()->json(Artisan::output());
    }


    /**
     * @return mixed
     */
    public function tespdtUateonpackage()
    {

        return BrandCtrl::getAllBrands();

    }
    public function CheckEmail(Request $request){
        $validator = Validator::make($request->all(), [
            'email' => 'required|email'
        ]);

        if ($validator->fails()) {
            return ['errors' => $validator->errors()];
        }
        $email=$request->email;
        $member=Member::where("email",$email)->first();
        if ($member){
            return response()->json(['message' => 'email exist']);
        }
        else{
            $Key = str_random(32);
            DB::table('login_keys')->insert(
                [
                    'email'=>$request->email,
                    'key'=>$Key,
                    'created_at'=>Carbon::now()
                ]
            );
            return response()->json([
                'errors' => ['email' => 'No user with that email'],
                'key'=>$Key
            ]);
        }

    }




}
