<?php

namespace App\Repositories\Member\Auth;

use App\Models\Affiliator;
use App\Models\Customer;
use App\Models\User;
use App\Models\UserDevice;
use App\Models\UserOtp;
use App\Models\VoucherEvent;
use Hash;
use Illuminate\Support\Facades\DB;
use App\Models\Role;
use Carbon\Carbon;
use Illuminate\Validation\ValidationException;
use App\Helpers\AutoNumbering;
use App\Repositories\Member\VoucherEvent\VoucherEventRepository;
use Exception;
use Illuminate\Support\Facades\Log;

class MemberAuthRepository
{

    var $voucherRepository;

    public function __construct(VoucherEventRepository $voucherRepository){
        $this->voucherRepository = $voucherRepository;
    }

    public function check($data)
    {
        $phone = $data['phone'] ?? null;
        $email = $data['email'] ?? null;

        if ($email) {
            return $this->findUserByEmail($email);
        }
        return $this->findUserByPhone($phone);
    }

    function generateUniqueOtp()
    {
        if (config('app.env') == 'local'){
            return 123456;
        }
        do {
            $otp = rand(100000, 999999);
        } while (UserOtp::where('otp', $otp)->where("expired_at",">", Carbon::now())->exists());

        return $otp;
    }

    private function findUserByPhone($phone){

        $phone = trim($phone);
        $phone = substr($phone,0,1) == "0" ? "62".substr($phone,1,strlen($phone)):$phone;
        $phone = preg_replace("/[^0-9]/", "",$phone);
        $phone_with_zero = "0" . substr($phone,2,strlen($phone));

        $customer = Customer::where('phone', $phone)->orWhere('phone', $phone_with_zero)->first();
        $user = @$customer->user;

        return $user;
    }


    private function findUserByEmail($email)
    {
        $email = trim($email);

        $customer = Customer::where('email', $email)->first();
        $user = @$customer->user;

        return $user;
    }

    public function findCustomerByEmail($email)
    {

        $email = trim($email);

        $customer = Customer::where('email', $email)->first();

        return $customer;
    }


    public function findCustomerById($id){

        $customer = Customer::where('id', $id)->first();

        return $customer;
    }


    public function findUserById($id){

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

        return $user;
    }


    public function waOtp($data)
    {
        $nextHour = Carbon::now()->addHour(1);
        // $user = $this->findUserByPhone($data["phone"]);
        $phone = $data['phone'];

        $otp = $this->generateUniqueOtp();
        $otp = UserOtp::create([
            'otp'=> $otp,
            'expired_at'=> $nextHour,
            'user_identity'=> $phone,
        ]);

        return $otp;
    }

    public function waOtpConfirm($data)
    {
        // $user = $this->findUserByPhone($data["phone"]);
        $phone = $data['phone'];

        if ($phone != "081111111111"){

            $otp = UserOtp::where('otp', $data['otp'])
            ->where("expired_at",">", Carbon::now())
            ->where('user_identity', $phone)
            ->orderBy('id','desc')
            ->first();

            if ($otp == null){
                throw ValidationException::withMessages([
                    "otp" => "Kode otp tidak valid!"
                ]);
            }
        }

        return $data;
    }

    public function emailOtp($data)
    {
        $nextHour = Carbon::now()->addHour(1);
        $email = $data['email'];
  

        $otp = $this->generateUniqueOtp();
        $otp = UserOtp::create([
            'otp'=> $otp,
            'expired_at'=> $nextHour,
            'user_identity'=> $email,
        ]);

        return $otp;
    }

    public function emailOtpConfirm($data)
    {
        // $user = $this->findUserByEmail($data["email"]);
        $email = $data['email'];
        
        $otp = UserOtp::where('otp', $data['otp'])
            ->where("expired_at",">", Carbon::now())
            ->where('user_identity', $email)
            ->orderBy('id','desc')
            ->first();

        if ($otp == null){
            throw ValidationException::withMessages([
                "otp" => "Kode otp tidak valid!"
            ]);
        }
        

        return $data;
        
    }

    public function getAuth($data)
    {
        $user_id = $data["user_id"] ?? null;
        $phone = $data["phone"] ?? null;
        $email = $data["email"] ?? null;
        $token = $data["token"] ?? null;
        

        $user = null;
        $customer = null;
        try{
            if ($user_id != null){
                $user = $this->findUserById($user_id);
            }else if ($phone != null) {
                $user = $this->findUserByPhone($data["phone"]);
            } else if ($email != null) {
                $user = $this->findUserByEmail($data["email"]);
            }

            if ($user != null) {

                $user->fill([
                    "fcm_token" => @$data["fcm_token"]
                ]);
                $user->save();
                $token = $user->createToken("pos");

                $customer = Customer::where("user_id", $user->id)->first();
                if (!@$customer->verified_at){
                    $customer->verified_at = Carbon::now();
                    $customer->save();
                }

                $device  = @$data["device"] ?? "default";
                $userDevice = UserDevice::where('user_id', $user->id)
                    ->where("device", $device)
                    ->firstOrNew();

                $userDevice->fill([
                    "user_id" => $user->id,
                    "ip_address" => request()->ip(),
                    "user_agent" => request()->userAgent(),
                    "last_login_at" => Carbon::now(),
                    "fcm_token" =>@$data["fcm_token"],
                    "device" => $device
                ]);

                $userDevice->save();
            }
        }catch(Exception $e){
            
        }

        return [
            "user" => $user,
            "token" => $token,
            "affiliator" => $user != null ? Affiliator::where("user_id", $user->id)->first() : null,
            "customer" => $customer,
        ];
    }

    


    public function otpByUserId($user_id)
    {
        $nextHour = Carbon::now()->addHour(1);
        $user = $this->findUserById($user_id);

        if ($user == null){
            throw ValidationException::withMessages([
                "email" => "Email tidak terdaftar"
            ]);
        }

        $otp = $this->generateUniqueOtp();
        $otp = UserOtp::create([
            'otp'=> $otp,
            'expired_at'=> $nextHour,
            'user_id'=> $user->id,
        ]);

        return $otp;
    }

    public function otpConfirmByUserId($user_id, $otp)
    {
        $user = $this->findUserById($user_id);
        
        $otp = UserOtp::where('otp', $otp)
            ->where("expired_at",">", Carbon::now())
            ->where('user_id', $user->id)
            ->first();

        if ($otp == null){
            throw ValidationException::withMessages([
                "otp" => "Kode otp tidak valid!"
            ]);
        }
    
      

        return true;
    }

    public function register($data) {

        $customer = null;

        $phone = @$data["phone"];

        if ($phone != null) {
            $user = $this->findUserByPhone($phone); 
            Log::info(["check user" => (array) $user]);
        
        
            if ($user){

                throw ValidationException::withMessages([
                    "phone" => "Nomor telepon sudah terdaftar"
                ]);
            }

            $phone = $data["phone"];
            $phone = trim($phone);
            $phone = substr($phone,0,1) == "0" ? "62".substr($phone,1,strlen($phone)):$phone;
            $phone = preg_replace("/[^0-9]/", "",$phone);
            $phone_with_zero = "0" . substr($phone,2,strlen($phone));

            $customer = Customer::where('phone', $phone)->orWhere('phone',$phone_with_zero)->first();

            Log::info(["check customer" => (array) $customer]);
        }


        
        $email = $data["email"];
        if ($email){
            $email = trim($email);
            $email = strtolower($email);

            $check_email = Customer::where('email', $email)->first();
            if ($check_email){
                throw ValidationException::withMessages([
                    "email" => "Email sudah terdaftar"
                ]);
            }
        }

        try {
            DB::beginTransaction();

            $role = Role::where("name","CUSTOMER")->firstOrCreate([
                "name" => "CUSTOMER"
            ]);


            if ($customer == null){
                $autoNumbering = new AutoNumbering([
                    "type" => "CUST",
                    "prefix" => "CAPP",
                    "location_id" => 0,
                    "pad" => 9
                ]);
                do{
                    $number = $autoNumbering->getCurrent();
                    $count = Customer::where("number",$number)->count();
                }while($count > 0);

                $customer = Customer::create([
                    'number' => $number,
                    'name' => $data['name'],
                    'phone' => $data['phone'] ?? null,
                    'email' => $data['email'] ?? null,
                    'referal' => $data['referral'] ?? null,
                    'company' => 'AGI',
                    'gender' => @$data['gender'],
                    'date_of_birth' => @$data['date_of_birth'],
                    'created_at' => now(),
                    'updated_at' => now()
                ]);


                $user = User::create([
                    'name'=> $customer->name,
                    'email'=> $customer->number."@customer.asiagolf.id",
                    'password'=> "",
                    'role_id'=> $role->id,
                ]);

                if (config('feature.voucher_new_member')){

                    $voucherEvent = VoucherEvent::where("referral","ilike", "NEW_USER")->first();
                    if ($voucherEvent){
                        $this->voucherRepository->createVoucher($voucherEvent, $customer, $user, "FREE VOUCHER NEW USER", Carbon::now()->addDay(7)->endOfDay(), 400000);
                    }

                }

                if (@$data['referral']){
                    $voucherEvent = VoucherEvent::where("referral","ilike", @$data['referral'])->first();
                    if ($voucherEvent){
                        $this->voucherRepository->createVoucher($voucherEvent, $customer, $user, "FREE VOUCHER REFERAL", Carbon::now()->addMonth(3)->endOfDay(), 300000);
                    }
                }

                $customer->user_id = $user->id;
                $customer->save();
            }else{
                $customer->fill([
                    'name' => $data['name'],
                    'phone' => $data['phone'],
                    'referal' => $data['referal'] ?? null,
                    'email' => $data['email'] ?? null,
                    'company' => 'AGI',
                    'gender' => @$data['gender'],
                    'date_of_birth' => @$data['date_of_birth'],
                    'created_at' => now(),
                    'updated_at' => now()
                ]);
                $user = User::find($customer->user_id);
                if ($user == null){

                    $user = User::create([
                        'name'=> $customer->name,
                        'email'=> $customer->number."@customer.asiagolf.id",
                        'password'=> "",
                        'role_id'=> $role->id,
                    ]);
                    $customer->user_id = $user->id;

                    if (config('feature.voucher_new_member')){

                        $voucherEvent = VoucherEvent::where("referral","ilike", "NEW_USER")->first();
                        if ($voucherEvent){
                            $this->voucherRepository->createVoucher($voucherEvent, $customer, $user, "FREE VOUCHER NEW USER", Carbon::now()->addDay(7)->endOfDay(), 400000);
                        }
                    }

                }
                $customer->save();
            }

            DB::commit();
            return $customer;

        } catch (\Exception $e) {
            DB::rollback();
            throw $e;
        }
    }

    public function loginGoogle($name, $email, $photo = null)
    {
        // check users table
        $user = User::where('email', $email)->first();

        if ($user == null) {
            $role = Role::where("name","CUSTOMER")->firstOrCreate([
                "name" => "CUSTOMER"
            ]);

            $user = User::create([
                'name'=> $name,
                'email'=> $email,
                'password'  => bcrypt(str()->random(8) . uniqid()),
                'photo' => $photo,
                'role_id'=> $role->id, // customer
            ]);
        }
        
        return $user;
    }
}
