<?php

namespace App\Repositories\Member\Transaction;

use App\Repositories\Member\Voucher\VoucherRepository;
use App\Models\Transaction;
use App\Models\Customer;
use App\Models\TransactionDetail;
use App\Models\TransactionStatus;
use App\Models\TransactionPayment;
use App\Models\XenditLink;
use App\Models\Location;
use App\Models\Items;
use App\Models\ItemReference;
use App\Models\Voucher;
use App\Models\Cart;
use Illuminate\Support\Facades\DB;
use App\Helpers\AutoNumbering;
use App\Models\CustomerPoint;
use App\Repositories\Member\ShippingRepository;
use App\Repositories\Pos\InvoiceRepository;
use Illuminate\Validation\ValidationException;
use App\ThirdParty\Xendit\Xendit;
use App\Models\TransactionShipping;
use Carbon\Carbon;
use Exception;
use App\Repositories\Auth\RoleRepository;
use Illuminate\Support\Facades\Notification;
use App\Notifications\Member\Transaction\NewOrder;
use App\Notifications\Member\Transaction\OrderPaid;
use App\Notifications\Member\Transaction\OrderProcessed;
use App\Notifications\Member\Transaction\OrderOnDelivery;
use App\Notifications\Member\Transaction\OrderDelivered;
use App\Notifications\Member\Transaction\OrderCanceled;

class TransactionRepository
{

    var $shippingRepository;
    var $invoiceRepository;
    var $roleRepository;
    var $voucherRepository;
    var $xendit;

    public function __construct(ShippingRepository $shippingRepository,
        InvoiceRepository $invoiceRepository,
        VoucherRepository $voucherRepository,
        RoleRepository $roleRepository,
        Xendit $xendit) {
        $this->shippingRepository = $shippingRepository;
        $this->invoiceRepository = $invoiceRepository;
        $this->roleRepository = $roleRepository;
        $this->voucherRepository = $voucherRepository;
        $this->xendit = $xendit;
    }

    public function getList($params = [])
    {
        $customColumns = [
            'user.name' => 'users.name',
        ];

        $limit = @$params["limit"] ? (int) @$params["limit"] : 10;
        $sortColumn = @$params["sort"]["column"] ? (@$customColumns[$params["sort"]["column"]] ? $customColumns[$params["sort"]["column"]]  : $params["sort"]["column"]) : "id";
        $sortDir = @$params["sort"]["dir"] ? $params["sort"]["dir"] : "desc";

        $model = Transaction::select('transactions.*')
        ->leftJoin('address', 'address.id', 'transactions.address_id')
        ->leftJoin('users', 'users.id', 'transactions.user_id')
        ->when(@!$params['is_admin'], function ($query) {
            $query->where('transactions.user_id', auth()->user()->id);
        })
        ->when(@$params['status'], function ($query) use ($params)  {
            $query->where('transactions.status', $params['status']);
        })
        ->when(@$params['filter']['multiple_status'] && !empty($params['filter']['multiple_status']), function($query) use ($params){
            $query->whereIn("transactions.status", $params['filter']['multiple_status']);
        })
        ->when(@$params['filter']['except'], function($query) use ($params){
            $except = @$params['filter']['except'];
            if (is_array($except)){
                $query->whereNotIn("status", $except);
            }else{
                $query->where("status","<>", $except);
            }
        })
        ->when(@$params['filter']['start'], function($query) use ($params){
            $query->whereDate("transactions.time", ">=", $params['filter']['start']);
        })
        ->when(@$params['filter']['end'], function($query) use ($params){
            $query->whereDate("transactions.time", "<=", $params['filter']['end']);
        })
        ->when(@$params['search'], function($query) use ($params) {
            $query->where(function($query) use ($params) {
                $query->where('transactions.number', 'ilike', '%' . $params['search'] . '%')
                ->orWhere('users.name', 'ilike', '%' . $params['search'] . '%')
                ->orWhere('address.name', 'ilike', '%' . $params['search'] . '%');
            });
        })
        ->orderBy($sortColumn, $sortDir)
        ->paginate($limit);

        return $model;
    }

    public function getListForExport($params = [])
    {
        $customColumns = [
            'user.name' => 'users.name',
        ];

        $limit = @$params["limit"] ? (int) @$params["limit"] : 10;
        $sortColumn = @$params["sort"]["column"] ? (@$customColumns[$params["sort"]["column"]] ? $customColumns[$params["sort"]["column"]]  : $params["sort"]["column"]) : "transactions.id";
        $sortDir = @$params["sort"]["dir"] ? $params["sort"]["dir"] : "desc";

        return Transaction::selectRaw("
            transactions.*,
            transaction_details.*,
            coalesce(item_variants.description, items.name) as product_name,
            item_reference.number as item_reference_number
        ")
        ->leftJoin('address', 'address.id', 'transactions.address_id')
        ->leftJoin('users', 'users.id', 'transactions.user_id')
        ->leftJoin('transaction_details', 'transaction_details.transaction_id', 'transactions.id')
        ->leftJoin('item_reference', 'item_reference.id', 'transaction_details.item_reference_id')
        ->leftJoin('items', 'items.id', 'item_reference.item_id')
        ->leftJoin('item_variants', 'item_variants.id', 'transaction_details.item_variant_id')
        ->when(@!$params['is_admin'], function ($query) {
            $query->where('transactions.user_id', auth()->user()->id);
        })
        ->when(@$params['status'], function ($query) use ($params)  {
            $query->where('transactions.status', $params['status']);
        })
        ->when(@$params['filter']['multiple_status'] && !empty($params['filter']['multiple_status']), function($query) use ($params){
            $query->whereIn("transactions.status", $params['filter']['multiple_status']);
        })
        ->when(@$params['filter']['except'], function($query) use ($params){
            $except = @$params['filter']['except'];
            if (is_array($except)){
                $query->whereNotIn("status", $except);
            }else{
                $query->where("status","<>", $except);
            }
        })
        ->when(@$params['filter']['start'], function($query) use ($params){
            $query->whereDate("transactions.time", ">=", $params['filter']['start']);
        })
        ->when(@$params['filter']['end'], function($query) use ($params){
            $query->whereDate("transactions.time", "<=", $params['filter']['end']);
        })
        ->when(@$params['search'], function($query) use ($params) {
            $query->where(function($query) use ($params) {
                $query->where('transactions.number', 'ilike', '%' . $params['search'] . '%')
                ->orWhere('users.name', 'ilike', '%' . $params['search'] . '%')
                ->orWhere('address.name', 'ilike', '%' . $params['search'] . '%');
            });
        })
        ->orderBy($sortColumn, $sortDir)
        ->get();
    }

    public function getCount($params = [])
    {
        $model = Transaction::select('transactions.*')
        ->leftJoin('address', 'address.id', 'transactions.address_id')
        ->leftJoin('users', 'users.id', 'transactions.user_id')
        ->when(@!$params['is_admin'], function ($query) {
            $query->where('transactions.user_id', auth()->user()->id);
        })
        ->when(@$params['status'], function ($query) use ($params)  {
            $query->where('transactions.status', $params['status']);
        })
        ->when(@$params['filter']['multiple_status'] && !empty($params['filter']['multiple_status']), function($query) use ($params){
            $query->whereIn("transactions.status", $params['filter']['multiple_status']);
        })
        ->when(@$params['filter']['except'], function($query) use ($params){
            $except = @$params['filter']['except'];
            if (is_array($except)){
                $query->whereNotIn("status", $except);
            }else{
                $query->where("status","<>", $except);
            }
        })
        ->select("status")
        ->addSelect(DB::raw("COUNT(*) as count"))
        ->groupBy("status")
        ->get();

        return $model;
    }

    public function getlistItem(Transaction $transaction, $params = []) {

        $limit = @$params["limit"] ? (int) @$params["limit"] : 10;
        $sortColumn = @$params["sort"]["column"] ? $params["sort"]["column"] : "id";
        $sortDir = @$params["sort"]["dir"] ? $params["sort"]["dir"] : "desc";

        return TransactionDetail::select('transaction_details.*')
        ->leftJoin('item_reference', 'item_reference.id', 'transaction_details.item_reference_id')
        ->leftJoin('item_variants', 'item_variants.id', 'transaction_details.item_variant_id')
        ->where('transaction_id', $transaction->id)
        ->when(@$params['search'], function($query) use ($params) {
            $query->where(function($query) use ($params) {
                $query->where('item_variants.description', 'ilike', '%' . $params['search'] . '%')
                    ->orWhere('item_reference.number', 'ilike', '%' . $params['search'] . '%');
            });
        })
        ->orderBy($sortColumn, $sortDir)
        ->paginate($limit);
    }

    public function setStatusTransaction($transactionId, $status, $note = '')
    {
        $user =  auth()->user();
        TransactionStatus::create([
            'transaction_id' => $transactionId,
            'time' => now(),
            'note' => $note,
            'status' => $status,
            'user_id' => @$user->id ?? 0,
        ]);
    }

    public function getAmount($items)
    {
        $amount = 0;

        foreach ($items as $detail)
        {
            $itemReference = ItemReference::findOrFail($detail['item_reference_id']);
            $item = Items::findOrFail($itemReference->item_id);
            $amount += $detail['qty'] * $item->unit_price;
        }

        return $amount;
    }


    public function createPayment($model){

        $fees = [];
        if ($model->shipping_price){
            $fees[] =
                [
                    "type" => "SHIPPING",
                    "value" => $model->shipping_price
                ];
        }
        if ($model->discount){
            $fees[] =
            [
                "type" => "DISCOUNT",
                "value" => $model->discount
            ];
        }

        $remaining_amount = ($model->subtotal + $model->shipping_price) - $model->discount;

        $xendit_response = $this->xendit->createPaymentLink([
            "external_id" => $model->number,
            "amount" => $remaining_amount,
            "items" => $model->details->map(function($cart){
                return [
                    "name" => $cart->item->name,
                    "category" => @$cart->item->category->name ?? "GOODS",
                    "price" => $cart->unit_price,
                    "quantity" => $cart->qty
                ];
            }),
           "fees" => $fees
        ]);


        if ($xendit_response){
            $xendit_link = XenditLink::create([
                "uid" => $xendit_response["id"],
                "invoice_url" => $xendit_response["invoice_url"],
                "user_id" => $xendit_response["user_id"],
                "external_id" => $xendit_response["external_id"],
                "status" => $xendit_response["status"],
                "amount" => $xendit_response["amount"],
                "expiry_date" => $xendit_response["expiry_date"]
            ]);
            $payment = TransactionPayment::create([
                "amount" => $remaining_amount,
                "status" => "PENDING",
                "transaction_id" => $model->id,
                "method_type" => get_class($xendit_link),
                "method_id" => $xendit_link->id
            ]);
        }
        $this->setStatusTransaction($model->id, 'WAIT_PAYMENT');
        return  $xendit_response;
    }


    public function create($data)
    {
        $model = DB::transaction(function () use ($data) {
            $user = auth()->user();
            $customer = Customer::where("user_id", $user->id)->first();
            $location_id = $data["location_id"];


            // validasi voucher
            if ( @$data["vouchers"]){
                $used_voucher = Voucher::whereIn("id", $data["vouchers"])->whereNotNull("used_at")->count();
                if ($used_voucher){
                    throw ValidationException::withMessages([
                        "voucher" => "Voucher Telah digunakan "
                    ]);
                }
            }

            // get numbering
            $auto = new AutoNumbering([
                "type" => "TRX",
                "location_id" => 0,
                "prefix" => "TRX",
                "pad" => 12
            ]);
            $number = $auto->getCurrent();
            $data["number"] = $number;

            $items = collect(@$data["items"] ?? []);

            $carts = Cart::where('user_id', $user->id)
                ->where("location_id", $data["location_id"])
->when(count($items) > 0, function($query) use ($items) {
            $query->whereIn("item_reference_id", $items->pluck("item_reference_id"));
})
                ->get();
            $carts = $carts->map(function($cart) use ($items){
                $item = $items->firstWhere("item_reference_id", $cart->item_reference_id);
                if ($item){
                    $cart->new_qty = $cart->qty - $item["qty"];
                    $cart->qty = $item["qty"];
                }
                return $cart;
            });

            if (count($carts) == 0){
                throw ValidationException::withMessages([
                    "items" => "Tidak ada item di keranjang"
                ]);
            }

            // detail data process
            $subtotal = 0;
            $details = [];
            foreach ($carts as $detail)
            {
                $convertion = 1;
                if (@$detail->item->display_unit and @$detail->item->display_unit != @$detail->item->unit){
                    $convertions =  DB::select("select to_qty / from_qty as conv from item_convertions where from_unit = ? and to_unit =  ?", [$detail->item->display_unit, $detail->item->unit] );
                    $convertion = max((float) @$convertions[0]->conv, 1);
                }
                $d_price = @$detail->itemReference->discount->price ?? 0;
                $s_price = @$detail->itemReference->price->price ?? 0;
                $price = ( $s_price ? $s_price : $detail->item->net_price) * $convertion;
                $price = ( $d_price ? $d_price : $price) * $convertion;
                $total = $detail->qty * $price;
                $details[] = [
                    'item_id' => $detail->item_id,
                    'item_variant_id' => $detail->item_variant_id,
                    'item_reference_id' => $detail->item_reference_id,
                    'qty' => $detail->qty,
                    'unit' => ($detail->item->display_unit ?? $detail->item->unit),
                    'unit_price' => $price,
                    'unit_cost' => $detail->item->unit_cost,
                    'total' => $total
                ];
                $subtotal += $total;
            }


            // validasi voucher
            if ( @$data["vouchers"]){
                $used_vouchers = Voucher::whereIn("id", $data["vouchers"])->get();
                foreach($used_vouchers as $v){
		if ($subtotal < ((float) $v->min_sales)){
                    throw ValidationException::withMessages([
                        "voucher" => "Voucher minimal belanja ".$v->min_sales
                    ]);
                }
                }
            }


            // get shipping_price
            $list_shipping = $this->shippingRepository->getList($data);
            $filtered_shipping = collect($list_shipping["pricing"])->filter(function($pricing) use ($data){
                return $pricing["company"] == $data["courier_company"] &&
                    $pricing["type"] == $data["courier_type"];
            })->values();
            if (count($filtered_shipping) == 0){
                throw ValidationException::withMessages([
                    "courier_company" => "Pilihan kurir tidak ditemukan"
                ]);
            }
if ($subtotal >= 1000000){
            $shipping_price = max($filtered_shipping[0]["price"] - 50000, 0);
}else{
            $shipping_price = $filtered_shipping[0]["price"];
}
            $valid_vouchers = $this->voucherRepository->getValidByItems($carts, $customer->id);
            $vouchers = @$data["vouchers"] ? Voucher::whereIn("id", $data["vouchers"])
                ->whereIn("id",$valid_vouchers)
                ->get(): collect([]);
            
            // discount
            $discount = $vouchers->reduce(function($acc, $voucher){
                return $acc + ($voucher->nominal);
            },0);

            $subtotal2 = $subtotal + $shipping_price;
            $amount = max(0, $subtotal2 - $discount);
            $discount = min($subtotal2, $discount);


            // discount points
            $discount_point = 0;
            $use_customer_points  = @$data["use_customer_points"] ?? 0;
            if ($use_customer_points > 0){
                $current_point = auth()->user()->customer->point;

                // use_customer_points
                if ($use_customer_points > $current_point){
                    throw ValidationException::withMessages([
                        "use_customer_points" => "Point tidak cukup. Poin anda " . number_format($current_point, 0, ",", ".")
                    ]);
                }


                // convert point to amount
                $point_to_amount = $use_customer_points * 1000;

                $discount_point = min($point_to_amount, $amount);

                $amount = max(0, $amount - $discount_point);
            }


            $model = Transaction::create([
                'number' => $data['number'],
                'address_id' => $data['address_id'],
                'location_id' => $data['location_id'],
                'courier_company' => $data['courier_company'],
                'courier_type' => $data['courier_type'],
                'shipping_price' => $shipping_price,
                'user_id' => auth()->user()->id,
                'customer_id' => @$customer->id,
                'time' => now(),
                'subtotal' => $subtotal,
                'discount' => $discount,
                'point' => $discount_point,
                'amount' => $amount,
                'status' => 'WAIT_PAYMENT',
            ]);
            $model->details()->createMany($details);


            $subtotal_remaining  = $subtotal2;
            foreach ($vouchers as $voucher) {
                if ($subtotal_remaining <= 0){
                    continue;
                }

                $voucher->fill([
                    "used_at" => Carbon::now(),
                    "reference_used_id" =>  $model->id,
                    "reference_used_type" => get_class($model)
                ]);
                $voucher->save();

                TransactionPayment::create([
                    "amount" => min($voucher->nominal, $subtotal_remaining),
                    "status" => "PAID",
                    "transaction_id" => $model->id,
                    "method_type" => get_class($voucher),
                    "method_id" => $voucher->id
                ]);

                $subtotal_remaining = max(0,$subtotal_remaining - $voucher->nominal);
            }

            if ($use_customer_points > 0){
                $cp = CustomerPoint::create([
                    "customer_id" => $model->customer_id,
                    "point" => -1 * $use_customer_points,
                    "reference_type" => get_class($model),
                    "reference_id" => $model->id,
                    "description" => "Discount Point",
                ]);

                $current_point = auth()->user()->customer->point;

                if ($current_point < 0){
                    throw ValidationException::withMessages([
                        "use_customer_points" => "Point anda telah habis"
                    ]);
                }

                TransactionPayment::create([
                    "amount" => $discount_point,
                    "status" => "PAID",
                    "transaction_id" => $model->id,
                    "method_type" => get_class($cp),
                    "method_id" => $cp->id
                ]);
            }

            // create payment
            $fees = [
                [
                    "type" => "SHIPPING",
                    "value" => $shipping_price
                ]
            ];
            if ($discount){
                $fees[] =
                [
                    "type" => "DISCOUNT",
                    "value" => $discount
                ];
            }
            $remaining_amount = $amount;
            if ($amount > 0){
                $xendit_response = $this->xendit->createPaymentLink([
                    "external_id" => $model->number,
                    "amount" => $remaining_amount,
                    "items" => $carts->map(function($cart){
$detail = $cart;
                $convertion = 1;
                if (@$detail->item->display_unit and  @$detail->item->display_unit != @$detail->item->unit){
                    $convertions =  DB::select("select to_qty / from_qty as conv from item_convertions where from_unit = ? and to_unit =  ?", [$detail->item->display_unit, $detail->item->unit] );
                    $convertion = max((float) @$convertions[0]->conv, 1);
                }

                $d_price = @$detail->itemReference->discount->price ?? 0;
                $s_price = @$detail->itemReference->price->price ?? 0;
                $price = ( $s_price ? $s_price : $detail->item->net_price) * $convertion;
                $price = ( $d_price ? $d_price : $price) * $convertion;

                        return [
                            "name" => $cart->item->name,
                            "category" => @$cart->item->category->name ?? "GOODS",
                            "price" => $price,
                            "quantity" => $cart->qty
                        ];
                    }),
                    "fees" => $fees
                ]);

                if ($xendit_response){

                    $xendit_link = XenditLink::create([
                        "uid" => $xendit_response["id"],
                        "invoice_url" => $xendit_response["invoice_url"],
                        "user_id" => $xendit_response["user_id"],
                        "external_id" => $xendit_response["external_id"],
                        "status" => $xendit_response["status"],
                        "amount" => $xendit_response["amount"],
                        "expiry_date" => $xendit_response["expiry_date"]
                    ]);

                    $payment = TransactionPayment::create([
                        "amount" => $remaining_amount,
                        "status" => "PENDING",
                        "transaction_id" => $model->id,
                        "method_type" => get_class($xendit_link),
                        "method_id" => $xendit_link->id
                    ]);
                }

                $this->setStatusTransaction($model->id, 'WAIT_PAYMENT');
            }else{
                $model->status = 'WAIT_PROCESS';
                $model->save();
                $this->setStatusTransaction($model->id, 'WAIT_PROCESS');
            }


            // clear cart

            foreach($carts as $cart){
                if ($cart->new_qty <= 0){
                    $cart->delete();
                }else{
                    $new_qty = $cart->new_qty;
                    unset($cart->new_qty);
                    $cart->update([
                        "qty" => $new_qty
                    ]);
                }
            }

            return $model;
        });

        return $model;
    }

    public function webhookPayment($data)
    {
        $paymentLink = XenditLink::where("uid", $data["id"])->firstOrFail();
        $paymentLink->fill([
            "payment_id" =>  @$data["payment_id"],
            "paid_amount" =>  @$data["paid_amount"],
            "payment_method" =>  @$data["payment_method"],
            "bank_code" =>  @$data["bank_code"],
            "payment_channel" =>  @$data["payment_channel"],
            "payment_destination" =>  @$data["payment_destination"],
            "received_amount" => @$data["adjusted_received_amount"],
            "status" =>  @$data["status"],
            "paid_at" =>  @$data["paid_at"]
        ]);
        $paymentLink->save();
        $paymentLink->payment()->update([
            "status" => $paymentLink->status,
        ]);

        $transaction = Transaction::find($paymentLink->payment->transaction_id);
        if ($transaction && @$data["status"] == "PAID"){

            if ($transaction->status != "WAIT_PROCESS"){ // once notify for first
                $roleRepository = $this->roleRepository;
                $users = $roleRepository->findUserByPermission("transaction.online");
                $notification = new NewOrder($transaction);
                Notification::send($users, $notification);

                $notification2 = new OrderPaid($transaction);
                $transaction->customer->user->notify($notification2);
            }

            $this->setStatusTransaction($transaction->id,'WAIT_PROCESS');
            $transaction->status = 'WAIT_PROCESS';
            $transaction->save();
        }else if ($transaction && @$data["status"] == "EXPIRED"){

            if ($transaction->status != "CANCELED"){
                $this->cancel($transaction->id,"Oleh System");
            }
        }

        return $paymentLink;
    }

    public function payment($id)
    {
        $model = DB::transaction(function () use ($id) {

            $model = Transaction::findOrfail($id);

            TransactionPayment::create([
                'transaction_id' => $model->id,
                'amount' => $model->amount,
                'status' => 'PAID',
            ]);

            $this->setStatusTransaction($model->id, 'WAIT_PROCESS');

            $model->status = 'WAIT_PROCESS';
            $model->save();

            return $model;
        });

        return $model;
    }

    public function process($id)
    {
        $repository = $this->invoiceRepository;
        $model = DB::transaction(function () use ($id, $repository) {

            $model = Transaction::findOrfail($id);

            $this->setStatusTransaction($model->id, 'ON_PROCESS');

            $model->status = 'ON_PROCESS';
            $model->save();

            $invoice = $this->invoiceRepository->createFromOnline($model);

            $vouchers = $model->vouchers;
            foreach ($vouchers as $voucher) {
                $repository->checkAffiliatorVoucher($invoice, $voucher);
            }

            return $model;
        });

        $user = @$model->customer->user;
        if ($user){
            $notification2 = new OrderProcessed($model);
            $user->notify($notification2);
        }

        return $model;
    }

    public function deliver($id)
    {
        $model = DB::transaction(function () use ($id) {

            $model = Transaction::findOrfail($id);

            $shipping = TransactionShipping::where("transaction_id",$model->id)->first();
            if ($shipping){
                return $model;
            }
            // order shippping
            $data = $this->shippingRepository->order($model);

            if(empty($data)) {
                throw new Exception('error failed create order');
            }

            $weight_total = collect($data["items"])->reduce(function($acc, $item){
                $item = (object) $item;
                return $acc + ($item->weight * $item->quantity);
            },0);

            $shipping = TransactionShipping::create([
                "transaction_id" => $model->id,

                "origin_address" => $data["origin"]["address"],
                "origin_name" => $data["origin"]["contact_name"],
                "origin_phone" => $data["origin"]["contact_phone"],
                "origin_postal_code" => $data["origin"]["postal_code"],
                "origin_latitude" => $data["origin"]["coordinate"]["latitude"],
                "origin_longitude" => $data["origin"]["coordinate"]["longitude"],
                "origin_note" => $data["origin"]["note"],


                "destination_address" => @$data["destination"]["address"],
                "destination_name" => @$data["destination"]["contact_name"],
                "destination_phone" => @$data["destination"]["contact_phone"],
                "destination_postal_code" => @$data["destination"]["postal_code"],
                "destination_latitude" => @$data["destination"]["coordinate"]["latitude"],
                "destination_longitude" => @$data["destination"]["coordinate"]["longitude"],
                "destination_note" => @$data["destination"]["note"],

                "shipper_name" => @$data["shipper"]["name"],
                "shipper_phone" => @$data["shipper"]["phone"],
                "shipper_email" => @$data["shipper"]["email"],

                "uid" => $data["id"],
                "tracking_id" => @$data["courier"]["tracking_id"],
                "waybill_id" => @$data["courier"]["waybill_id"],
                "company" => @$data["courier"]["company"],
                "driver_name" => @$data["courier"]["driver_name"],
                "driver_phone" => @$data["courier"]["driver_phone"],
                "driver_photo_url" => @$data["courier"]["driver_photo_url"],
                "driver_plate_number" => @$data["courier"]["driver_plate_number"],
                "type" => @$data["courier"]["type"],
                "insurance_amount" => @$data["insurance"]["amount"],
                "insurance_fee" => @$data["insurance"]["fee"],
                "weight_total" => $weight_total,
                "price" => @$data["price"],
                "note" => @$data["note"],
                "status" => @$data["status"]
            ]);

            $this->setStatusTransaction($model->id, 'ON_DELIVERY');

            $model->status = 'ON_DELIVERY';
            $model->save();


            return $model;
        });


        $user = @$model->customer->user;
        if ($user){
            $notification2 = new OrderOnDelivery($model);
            $user->notify($notification2);
        }

        return $model;
    }

    public function close($id)
    {
        $model = DB::transaction(function () use ($id) {

            $model = Transaction::findOrfail($id);

            $this->setStatusTransaction($model->id, 'CLOSED');

            $model->status = 'CLOSED';
            $model->save();

            return $model;
        });

        return $model;
    }

    public function delivered($id)
    {
        $model = DB::transaction(function () use ($id) {

            $model = Transaction::findOrfail($id);

            $this->setStatusTransaction($model->id, 'DELIVERED');

            $model->status = 'DELIVERED';
            $model->save();

            return $model;
        });

        $user = @$model->customer->user;
        if ($user){
            $notification2 = new OrderDelivered($model);
            $user->notify($notification2);
        }

        return $model;
    }

    public function cancel($id, $note = "")
    {
        $model = DB::transaction(function () use ($id, $note) {

            $model = Transaction::findOrfail($id);
            $model->vouchers()->update([
                "used_at" => null,
                "reference_used_id" => null,
                "reference_used_type" => null
            ]);

            $this->setStatusTransaction($model->id, 'CANCELED', $note);

            $model->status = 'CANCELED';
            $model->save();


           

            $customer_point = CustomerPoint::where("customer_id", $model->customer_id)
            ->where("reference_id", $model->id)
            ->where("reference_type", get_class($model))
            ->orderBy("id", "asc")
            ->first();

            if ($customer_point){
                 CustomerPoint::create([
                    "customer_id" => $model->customer_id,
                    "point" => -1 * $customer_point->point,
                    "reference_type" => get_class($model),
                    "reference_id" => $model->id,
                    "description" => "Refund Discount Point",
                ]);
            }


            return $model;
        });

        $user = @$model->customer->user;
        if ($user){
            $notification2 = new OrderCanceled($model);
            $user->notify($notification2);
        }

        return $model;
    }
}
