<?php

namespace App;

use DB;

use EF;
use App\Plot;
use App\Branch;
use App\CancelBooking;
use Spatie\Permission\Models\Role;
use Illuminate\Database\Eloquent\Model;

class Booking extends Model
{

   private $generic_condition;

   private $percentage;


    public function __construct()
    {

       $this->setCondition(['is_recycle' => '0']);

       $this->setPercentage(0.25);
    }

    public function setCondition($condition = [])
    {
        $this->generic_condition = $condition;
    }

    public function getCondition()
    {
        return $this->generic_condition;
    }

    public function setPercentage($per)
    {
        $this->percentage = $per;
    }

    public function getPercentage()
    {
        return $this->percentage;
    }

    public function verifiyExpireBooking()
    {
        $condition = $this->getCondition();
        $condition += ['status' => 'Reserved'];

        $expired_list = Booking::where($condition)->whereDate('reserve_edate','<=',date('Y-m-d'))->get();

        foreach ($expired_list as $rows)
        {
            $plot = new Plot;

            $plot->updatePlotStatus(['status'=> 'unsold'],$rows->plot_id);
        }

        return Booking::where($condition)->whereDate('reserve_edate','<=',date('Y-m-d'))->update(['status' => 'Expired']);
    }

    //RETRIEVING BOOKINGS  

    public function getBookingByBranch($branch_in = [],$condition_in = [])
    {
         $condition = $this->getCondition();

        return  Booking::where($condition)->whereIn('branch_id',$branch_in)->whereIn('status',$condition_in)->whereHas('plot')->whereHas('branch')->whereHas('user')->orderBy('id','asc')->get();
    }

    public function getBookingByPlotId($id)
    {
         $condition = $this->getCondition();

        return  Booking::where($condition)->where('plot_id',$id)->orderBy('id','asc')->first();
    }

    

    public function getBlockBookingByBranch($branch_in = [],$condition_in = [])
    {
         $condition = $this->getCondition() + ['is_block' => 1];


        return  Booking::where($condition)->whereIn('branch_id',$branch_in)->whereIn('status',$condition_in)->whereHas('plot')->whereHas('branch')->whereHas('user')->orderBy('id','asc')->get();
    }


    //RETRIEVING BOOKINGS THAT FULFILL CONDITION
    public function getAllBookings($condition_in = [])
    {
         $condition = $this->getCondition();

        return  Booking::where($condition)->whereIn('status',$condition_in)->whereHas('plot')->whereHas('branch')->whereHas('user')->orderBy('id','asc')->get();
    }
      //GET APPROVE BOOKING COUNT BY Status
    public function getBookingsCountByStatus($status =[])
    {
        $condition = $this->getCondition();

        return Booking::where($condition)->whereIn('status',$status)->count();

    }

     //RETRIEVING BOOKINg BY ID
    public function getBookingById($id)
    {
      $condition = $this->getCondition();
      $condition  += ['id' => $id];
        return Booking::where($condition)->first();

    }

    public function updateInstallmentMode($object)
    {
        return DB::transaction(function () use ($object) {

            $booking = Booking::find($object['booking_id']);

            $booking->installment_mode = $object['gap'];

            if($booking->update()){

                return $booking;

            }
            
            return false;

        });
    }

    public function markTag($id,$value,$column)
    {
         return DB::transaction(function () use ($id,$value,$column) {

            $booking = Booking::find($id);
            $view = '<tr></tr>';


            if(isset($booking->id))
            {
                if($column == 'is_hotitem')
                {
                    if($booking->is_hotitem == 0)
                    {
                        $booking->is_hotitem = 1;

                    }
                    else
                    {
                        $booking->is_hotitem = 0;

                    }
                }
                elseif($column == 'is_resale')
                {
                     if($booking->is_resale == 0)
                    {
                        $booking->is_resale = 1;

                    }
                    else
                    {
                        $booking->is_resale = 0;

                    }

                }
                 elseif($column == 'is_block')
                {
                     if($booking->is_block == 0)
                    {
                        $booking->is_block = 1;

                    }
                    else
                    {
                        $booking->is_block = 0;

                    }

                }

                else
                {
                    return 0;
                }

                    $booking->update();



            }

            return with($booking);
        });

    }


    //STORING NEW BOOKING
    public function storeBooking($object)
    {

        return DB::transaction(function () use ($object)  {

            $booking = new Booking;

            $label_list = EF::getWhiteLabel();

            $booking->branch_id                         = $object[$label_list['branch']];
            $booking->user_id                           = $object['user_id'];
            $booking->plot_id                           = $object[$label_list['plot']];
            $booking->ms                                = $this->generateMsNumber();
            $booking->file_number                       = $object[$label_list['file']];
            $booking->reference_number                  = $object[$label_list['reference']];
            $booking->feature_description               = NULL;
            $booking->discount                          = $object[$label_list['discount']];
            $booking->feature_charges                   = $object[$label_list['feature_charges']];
            $booking->rate_per_marla                    = $object[$label_list['total_amount']];
            $booking->agreed_amount                     = $object[$label_list['agreed_amount']];
            // $booking->receipt_number                    = $object[$label_list['receipt']];
            // $booking->token_amount                      = $object[$label_list['token_amount']];
            // $booking->mode                              = $object[$label_list['payment_mode']];
            // $booking->drawn_on                          = $object['drawn_on'];
            // $booking->instrument                        = $object['instrument'];
            // $booking->instrument_date                   = $object['instrument_date'];
            $booking->approve_date                      = NULL;
            $booking->finger_print                      = NULL;
            $booking->print_width                       = NULL;
            $booking->raw_data                          = NULL;
            $booking->remarks                           = $object[$label_list['remarks']];

            $booking->is_reserve                        = $object['reserve'];
            $booking->status                            = $object['status'];
            // $booking->reserve_sdate                     = $object['reserve_sdate'];
            $booking->reserve_edate                     = $object['reserve_edate'];
            $booking->approve_date                      = $object['approve_date'];



            $booking->created_at                        = date('Y-m-d',strtotime($object[$label_list['booking_date']]));



            $booking->save();

            // Update User Role with Customer.

          
            $user = new User;
            $role = new Role;

            $curr_user = $user->getUserById($object['user_id']);

            if (isset($curr_user->id)) {
                // user found now check for customer role.
                $roles = $curr_user->getCurrentUserRolesArrayWithColumn('name');
                if (!in_array('Customer', $roles)) {
                    // assign customer role to user.
                    $roles = $curr_user->getCurrentUserRolesArrayWithColumn('id');
                    // dd($roles);
                    $customer_role = $role->findByName('Customer');
                    $roles[] = $customer_role->id;
                    $curr_user->assignRole($roles);
                }
            }
            //UPDATING PLOT STATUS TO SOLD
            $plot = new Plot;

            $plot->updatePlotStatus(['status'=> $object['plot_status']],$object[$label_list['plot']]);

            // COMMISSION SECTION
            $commission = new Commission;

            $salesperson_list = [];
            $dealer_list      = [];

            if(isset($object['employee']))
            {
              $salesperson_list = $object['employee'];
            }

            if(isset($object['dealer']))
            {
              $dealer_list = $object['dealer'];
            }

            foreach ($salesperson_list as $rows)
            {
                $data = [

                    'user_id'           =>  ($rows),
                    'booking_id'        =>  $booking->id,
                    'role_id'           =>  EF::getRoleIdbyName('Employee'),
                    'payment_type'      => 'Commission',
                    'description'       => 'Employee Commission',
                    'percentage'        => 0,
                    'amount'            => 0,
                ];



                $commission->storeCommission($data);
            }

            foreach ($dealer_list as $rows)
            {

                $data = [

                    'user_id'           =>  ($rows),
                    'booking_id'        =>  $booking->id,
                    'role_id'           =>  EF::getRoleIdbyName('Dealer'),
                    'payment_type'      => 'Commission',
                    'description'       => 'Dealer Commission',
                    'percentage'        => 0,
                    'amount'            => 0,
                ];

                $commission->storeCommission($data);
            }

            // END SECTION


            return with($booking);

        });
    }

    public function updateBooking($object)
    {

        return DB::transaction(function () use ($object)  {

            $booking =  Booking::find($object['booking_id']);


            $label_list = EF::getWhiteLabel();

            if(isset($booking->id))
            {

                // UPDATE BOOKING PART

                $booking->file_number                       =  $object[$label_list['file']];
                $booking->reference_number                  =  $object[$label_list['reference']];
                // $booking->mode                              =  $object[$label_list['payment_mode']];
                // $booking->drawn_on                          =  $object['drawn_on'];
                // $booking->instrument                        =  $object['instrument'];
                // $booking->instrument_date                   =  $object['instrument_date'];

                $booking->remarks                           =  $object[$label_list['remarks']];
                  // $booking->receipt_number                    = $object[$label_list['receipt']];


                $booking->created_at                        =  date('Y-m-d',strtotime($object[$label_list['booking_date']]));
                if($booking->status == 'Unapprove')
                {
                    $booking->branch_id                         = $object[$label_list['branch']];

                    $booking->discount                          = $object[$label_list['discount']];
                    $booking->feature_charges                   = $object[$label_list['feature_charges']];
                    $booking->rate_per_marla                    = $object[$label_list['total_amount']];
                    $booking->agreed_amount                     = $object[$label_list['agreed_amount']];
                    // $booking->receipt_number                    = $object[$label_list['receipt']];

                    // $booking->token_amount                      = $object[$label_list['token_amount']];


                    // UPDATING PLOT IF CLENT AND CURRENT BOOKING PLOT NOT MATCH

                    if($booking->plot_id != $object[$label_list['plot']])
                    {
                        // FIRST PLOT STATUS SOLD FOR NEW PLOT

                        // SECOND PLOT STATUS UNSOLD FOR PREVIOUS PLOT
                        $plot = new Plot;

                        $plot->updatePlotStatus(['status'=> 'sold'],$object[$label_list['plot']]);

                        $plot = new Plot;

                        $plot->updatePlotStatus(['status'=> 'unsold'],$booking->plot_id);

                        $booking->plot_id = $object[$label_list['plot']];
                    }



                }


                $booking->update();

                // END UPDATE BOOKING PART

                return with($booking);

            }

        });
    }

    public function updateStatus($id,$status)
    {
        return \DB::transaction(function () use ($id,$status) {

            $booking = Booking::find($id);

            if(isset($booking->id))
            {

                // ONLY FOR RESERVE BOOKING
                if($booking->status == "Reserved")
                {
                    $plot = new Plot;

                    $plot->updatePlotStatus(['status'=> 'sold'],$booking->plot_id);
                }

                $booking->status  = $status;

                $booking->update();

            }

            return with($booking);
        });
    }

    public function approveBooking($object)
    {
          return DB::transaction(function () use ($object) {

            $booking = Booking::find($object['id']);

            if(isset($booking->id)&& $booking->status == "Unapprove")
            {
                if(date('Y-m-d',strtotime($object['approve_date'])) >= date('Y-m-d',strtotime($booking->created_at)))
                {

                        $booking->status  = 'Approve';

                        $booking->approve_date = date('Y-m-d',strtotime($object['approve_date']));


                        $booking->update();

                        $token_object['plan_type']  = NULL;
                        $token_object['booking_id'] = $booking->id;
                        $token_object['user_id']    = $booking->user_id;
                        $token_object['user_id']    = $booking->user_id;
                        $token_object['payment_type'][0] = "Token";
                        $token_object['amount'][0]       = $booking->token_amount;
                        $token_object['description'][0]   = "Token";
                        $token_object['date'][0] = date('Y-m-d',strtotime($booking->created_at));

                        if($booking->token_amount > 0)
                        {
                            $installment = new Installment;

                            $installment->storePlan($token_object);

                        }

                        $payment = new Payment;

                        // 1 MEAN BOOKING RECEIVABLE ACCOUNT
                        // 2 MEAN BOOKING REVENUE ACCOUNT
                        // THIS IS AUTO BOOKING JV FUNCTION
                        // $transaction = $payment->createBookingJv($booking,1,2);

                        $data['booking'] = $booking;
                        // $data['transaction'] = $transaction;
                        // $data['transaction'] =false;

                        return with($data);
                }
                else
                {
                    return 2;
                }

            }

            return 0;
        });
    }

    public function removeBooking($id)
    {
          return DB::transaction(function () use ($id) {

            $booking = Booking::find($id);

            if(isset($booking->id))
            {

                $booking->is_recycle   = '1';

                $booking->update();
            //UPDATING PLOT STATUS TO UNSOLD
                $plot = new Plot;

                $plot->updatePlotStatus(['status'=> 'unsold'],$booking->plot_id);

                // $this->removeBookingLedger($booking->id);
            }

            return with($booking);
        });
    }

    public function removeBookingLedger($booking_id)
    {
        $payment = new Payment;

        $payment->removeBulkPayment('Booking',$booking_id);

        // REMOVE INSTALLMENT
        $installment = new Installment;

        $installment->removeBulkInstallment($booking_id);

        $payment->removeBulkPayment('Installment',$booking_id);


        // END REMOVE INSTALLMENT

        // REMOVE COMMISSION
        $commission = new Commission;

        $commission->removeBulkCommission($booking_id);

        $payment->removeBulkPayment('Commission',$booking_id);
        // END REMOVE COMMISSION

        $journal = new Journal;

        $journal->removeBulkJournal($booking_id);

        $transfer = new Transfer;

        $cancel = new CancelBooking;

        $cancel->removeBulkCancelBooking($booking_id);

        $transfer->removeBulkTransfer($booking_id);
    }


    public function updateSoftBooking($object)
    {
          return DB::transaction(function () use ($object) {

            $booking = Booking::find($object['id']);



            if(isset($booking->id))
            {
                $end_date = date('Y-m-d',strtotime($object['end_date']));

                $start_date = date('Y-m-d',strtotime($booking->created_at));

                if($end_date > $start_date  )
                {
                    $curr_plot = $booking->plot;

                    if($booking->status == "Reserved" && $curr_plot->status != "sold")
                    {

                        $plot = new Plot;

                        $plot->updatePlotStatus(['status'=> 'reserve'],$booking->plot_id);

                        $booking->reserve_edate = date('Y-m-d',strtotime($object['end_date']));

                        $booking->status = "Reserved";

                        $booking->update();

                        return with($booking);

                    }
                    else if($booking->status == "Expired" && $curr_plot->status == "unsold")
                    {
                        $plot = new Plot;

                        $plot->updatePlotStatus(['status'=> 'reserve'],$booking->plot_id);

                        $booking->reserve_edate = date('Y-m-d',strtotime($object['end_date']));

                        $booking->status = "Reserved";

                        return with($booking);
                    }
                    else
                    {
                        // Plot is not availble
                        return 1;
                    }
                }
                else
                {
                    // Date Issue
                    return 2;
                }


            }
            //SOME THING IS WRONG
            return 0;
        });
    }


    public function approveCancelBooking($object)
    {
          return DB::transaction(function () use ($object) {


            $booking = Booking::find($object['booking_id']);
             $cancel_booking_obj = new CancelBooking;


            if(isset($booking->id))
            {
                $received_amount = $this->getBalanceDetail($booking->id)['debit'];

                $received_amount = $received_amount - $object['deduction_amount'];

                if($object['approval'] == 1)
                {


                // STEP RESERVE JV
                $transaction = new Transaction;
                $journal     = new Journal;
                $payment     = new Payment;


              ///  $jv_payment = $payment->getBookingPayments($booking->id,['Booking JV']);


                // if(isset($jv_payment[0]->id))
                // {
                //     $jv_journal = $journal->getJorunalByPaymentId($jv_payment[0]->id);

                //     if(isset($jv_journal->id))
                //     {
                //         $transaction->reverseVoucher($jv_journal->transaction,date('Y-m-d'),$booking->agreed_amount - $received_amount);
                //     }

                // }


              //  STEP 2 ADD PROFILE AND REFUND IN COMMISION
                $commission = new Commission;
                $object['user_id']   = $booking->user_id;

                $object['role_id']   = EF::getRoleIdByName('Customer');

                $object['user_type']  = $booking->user->type;
                $object['percentage'] = 0;

                if($received_amount > 0)
                {
                    $object['payment_type'] = 'Refund';
                    $object['description']  = 'Booking refund amount.';
                    $object['amount']       =  $received_amount;

                    $commission->storeCommission($object);
                }

                if($object['deduction_amount'] > 0)
                {
                    $object['payment_type'] = 'Deduction';
                    $object['description']  = 'Booking deduction / profit amount.';
                    $object['amount']       =  ($object['deduction_amount']);

                    $commission->storeCommission($object);
                }
                     //UPDATING PLOT STATUS TO UNSOLD
                $plot = new Plot;

                $plot->updatePlotStatus(['status'=> 'unsold'],$booking->plot_id);

                $update_cancel_status = $cancel_booking_obj->updateStatus($object['booking_id'],'Approve');


            }




                $object['refund_amount'] = $received_amount;

                $cancel_record_data = $cancel_booking_obj->updateCancelBooking($object);

            }

             return with($booking);
        });
    }


    public function getCancelBookings($status)
    {
           $condition = $this->getCondition();
           $condition  += ['status' => $status];

           return Booking::where($condition)->get();

    }


    //GENERATE MS NUMBER
    public function generateMsNumber()
    {
        $insert_id = booking::max('id');
        $serial = 'SL/'.str_pad(($insert_id+1), 4, '0', STR_PAD_LEFT);
        return $serial;

    }

    public function getBalanceDetail($booking_id)
    {
           $installment = new Installment;
           $condition = $this->getCondition();
           $condition += ['id' => $booking_id];
           $total = Booking::where($condition)->value('agreed_amount');
           $debit = $installment->sumOfReceivedInstallments($booking_id);
           $credit = $total - $debit;

           return ['total'=> $total,'debit'=> $debit,'credit'=> $credit]  ;

    }
    public function getMatureAll()
    {
        $mature = 0;
        $immature = 0;
       $bookings =  $this->getAllBookings(["Approve"]);
       foreach($bookings as $rows)
       {
        $balance_detail = $this->getBalanceDetail($rows->id);
        $expected_amount = ($balance_detail['total'] * $this->getPercentage());
        if($balance_detail['debit']>= $expected_amount)
        {
            $mature++;

        }
        else
        {
            $immature++;
        }
       }
       return ['mature'=> $mature,'immature'=> $immature];

    }

    public function getMatureByBooking($booking_id)
    {

        $balance_detail = $this->getBalanceDetail($booking_id);
        $expected_amount = ($balance_detail['total'] * $this->getPercentage());
        if($balance_detail['debit'] >= $expected_amount)
        {
            return true;

        }
        else

        {
            return false;
        }

    }

    public function getShortAmount($booking_id)
    {
         $installment = new Installment;

         $shortamount = $installment->SumofShortAmount($booking_id);

         return $shortamount;

    }

    public function bookingWiseReport($from,$to,$plot_condition = [],$booking_condition = [])
    {


        $booking_condition += $this->getCondition();
        return  Booking::with('plot')->


            whereHas('plot',function($query) use ($plot_condition){

             $query->where($plot_condition);

        })

        ->where($booking_condition)

        ->where($this->getCondition())

        ->whereDate('bookings.created_at','>=',$from)

        ->whereDate('bookings.created_at','<=',$to)

        ->get();

    }
        public function cancelBooking($object)
    {
          return DB::transaction(function () use ($object) {

            $booking = Booking::find($object['booking_id']);

            if(isset($booking->id) && $booking->status != "Cancel")
            {
                $received_amount = $this->getBalanceDetail($booking->id)['debit'];

                // STEP RESERVE JV
                $transaction = new Transaction;
                $journal     = new Journal;
                $payment     = new Payment;


                $received_amount = $received_amount - $object['deduction_amount'];


                $object['refund_amount'] = $received_amount;

                $cancel_booking_obj = new CancelBooking;

                $cancel_record_data = $cancel_booking_obj->storeCancelBooking($object);

                $booking->status = "Cancel";

                $booking->update();


            }

             return with($booking);
        });
    }

    public function getBookingByUserId($user_id)
    {

           $condition = $this->getCondition();
           $condition += ['user_id' => $user_id];
        return Booking::where($condition)->get();
    }

    public function getBookingByColumn($column,$value)
    {
         $condition = $this->getCondition();
         $condition += [$column => $value];
        return Booking::where($condition)->get();
    }

    public function getFingerPrintPlotBooking($user_id){

        $condition = $this->getCondition();

        $condition += ['user_id' => $user_id];

        return  Booking::where($condition)->whereHas('plot')->get();
    }

  //GET APPROVE BOOKING COUNT BY Status
    public function getBookingsCountByStatusBranchwise($status =[],$branch_ids= [])
    {
        $condition = $this->getCondition();

        return Booking::where($condition)->whereIn('status',$status)->branchwise($branch_ids)->count();

    }

    public function scopeBranchwise($query,$branch_ids){

        if(in_array(0,$branch_ids))
        {
            $branch_ids = Branch::where($this->getCondition())->pluck('id')->toArray();
        }

        

        return $query->whereIn('branch_id',$branch_ids);
    }
    public function getBookingByColumnBranchwise($column,$value,$branch_ids =[])
    {
         $condition = $this->getCondition();
         $condition += [$column => $value];
        return Booking::where($condition)->branchwise($branch_ids)->get();
    }
      // FORIGN KEY TYPE FUNCTION LIST
    public function branch()
    {
        return $this->belongsTo(Branch::class,'branch_id')->where($this->getCondition())->withDefault();
    }
    public function plot()
    {
        return $this->belongsTo(Plot::class,'plot_id')->withDefault();
    }

    public function user()
    {
        return $this->belongsTo(User::class,'user_id')->withDefault();
    }

    public function nominee()
    {
       return $this->belongsTo(Nominee::class,'booking_id')->where('nok_type','Nominee')->where($this->getCondition())->withDefault();
    }
    public function getSalesperson()
    {
        // return $this->hasMany('App\Comment');
    }
      public function cancelbookingrelation()
    {
        return $this->hasOne(CancelBooking::class)->withDefault();
    }



}
